關於.net託管環境下struct型別的記憶體佈局的認識
熟悉C/C++的朋友都知道,struct型別中的成員在記憶體中都是按順序依次存放的,即按成員的宣告順序,並且通常是按成員中佔用空間最大的成員進行對齊的。
然 而,到了.net託管環境中,則有所不同。CLR為我們提供了兩種不同的結構成員記憶體佈局方式:LayoutKind.Sequential和 LayoutKind.Explicit,分別實現常用的順序佈局和按偏移量精確佈局。前者是CLR的預設值。我們可以在宣告struct時加上修飾: [StructLayout(LayoutKind.Sequential)]來告訴CLR要採用的記憶體佈局方式為順序。採用這種佈局方式宣告的 struct在記憶體中和非託管環境中宣告的struct一致,所以,通常在和非託管Dll進行互動呼叫的時候,應將struct宣告成順序式的。看下面的 示例:
[StructLayout(LayoutKind.Sequential)]
struct S1 //16byte
{
int i; //4byte
double b; //8byte
}
按 順序佈局的S1本來只佔用了12個byte的記憶體空間,但是,當我們用sizeof(S1)測試的時候,發現它竟然佔用了16個byte的空間,這是因為 LayoutKind.Sequential(預設)情況下,CLR對struct的Layout的處理方法與C/C++中預設的處理方式相同,即按照結 構中佔用空間最大的成員進行對齊(Align)。顯然,這種方式浪費了一定的記憶體空間。
然而,按偏移量來佈局的方式也有一定的不足,當偏移量計算不準的時候,就會造成資料丟失。請看下面的示例:
[StructLayout(LayoutKind.Explicit)]
struct S2
{
[FieldOffset(0)] int i;
[FieldOffset(0)] double b;
}
S2中兩個成員的記憶體位置偏移量都是0,這就意味著它們佔用了相同的部分記憶體空間。當修改其中一個的值時,必然導致另一個的值也發生變化。因為,偏移量的計算應當非常小心才是。以下是一段來MSND上的比較好的例子:
using System.Runtime.InteropServices ;
[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}
細心的朋友可能發現:程式碼中用的是class面不是struct,這說明class和struct其實沒有本質的區別。再看一個使用順序方式的比較好的例子:
[StructLayout(LayoutKind.Sequential)]
public struct POINT {
public POINT(int xx, int yy) { x=xx; y=yy; } //建構函式
public int x;
public int y;
public override string ToString() {
String s = String.Format( "({0},{1}) ", x, y);
return s;
}
}
補充說明:
其實,.net中還有第三種佈局方式:[StructLayout(LayoutKind.Auto)]。這種方式下,CLR會對結構體中 的欄位順序進行調整使之佔用儘可能少的記憶體,也就是說,CLR會自動將struct中佔用空間多的排在前面,佔用空間少的排在後面,並進行4byte的內 存對齊,這樣下來,可以相比順序方式節省一定的記憶體,但還是比精確定義偏移量的方式多浪費一些記憶體。
有關.net託管環境下struct型別的記憶體佈局的問題,更多資訊可以閱讀網友happyhippy的博文:
http://www.cnblogs.com/happyhippy/archive/2007/04/12/710927.aspx
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-624903/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從C++看C#託管記憶體與非託管記憶體C++C#記憶體
- 關於不完全型別的認識型別
- 【記憶體管理】記憶體佈局記憶體
- Java物件的記憶體佈局Java物件記憶體
- JVM -- 物件的記憶體佈局JVM物件記憶體
- [CPP] 類的記憶體佈局記憶體
- 記Java中有關記憶體的簡單認識Java記憶體
- 託管堆記憶體佔用記憶體
- c程式的記憶體佈局圖C程式記憶體
- OC物件記憶體佈局物件記憶體
- Java物件記憶體佈局Java物件記憶體
- C程式記憶體佈局C程式記憶體
- [筆記]關於blade佈局的使用筆記
- 生產環境VS開發環境,關於Kubernetes的四大認識誤區開發環境
- 虛擬函式的記憶體佈局(上)函式記憶體
- 記一次 .NET 某智慧水廠API 非託管記憶體洩漏分析API記憶體
- 記一次 .NET 某桌面奇俠遊戲 非託管記憶體洩漏分析遊戲記憶體
- 分散載入與記憶體佈局記憶體
- Rust 程式設計:記憶體佈局Rust程式設計記憶體
- 10-記憶體空間佈局記憶體
- 記一次 .NET 某電子廠OA系統 非託管記憶體洩露分析記憶體洩露
- 認識各種記憶體地址記憶體
- 超大記憶體環境下的Oracle RAC引數設定建議記憶體Oracle
- JVM-物件及物件記憶體佈局JVM物件記憶體
- 關於JavaScript的記憶體機制JavaScript記憶體
- 關於hapypack的認識
- 博森量化軟體:託管錢包與非託管錢包的區別?
- 【知識分享】伺服器記憶體和普通記憶體的區別伺服器記憶體
- JVM中java例項物件在記憶體中的佈局JVMJava物件記憶體
- 深入理解 Python 的物件複製和記憶體佈局Python物件記憶體
- 物件的例項化、記憶體佈局以及訪問定位物件記憶體
- 關於flex佈局的應用Flex
- struct結構體大小的計算(記憶體對齊)Struct結構體記憶體
- SAP ABAP 的兩種記憶體物件型別記憶體物件型別
- Metasploit執行環境記憶體不要低於2GB記憶體
- C++ 虛繼承 物件記憶體佈局C++繼承物件記憶體
- 圖文詳解Java物件記憶體佈局Java物件記憶體
- 關於redis記憶體分析,記憶體優化Redis記憶體優化
- 關於 PHP 記憶體溢位的思考PHP記憶體溢位