[英]What is the memory overhead of a .NET custom struct type?
有一個與.NET對象相關的固定開銷,在這個SO問題中有更全面的概述: .NET對象的內存開銷是12或24字節,具體取決於你是在32位還是64位進程。
也就是說,像int, double, boolean
等基本值類型不會產生任何開銷,因為它們是值類型 。
在您的應用程序中放置自定義struct
類型的位置在哪里? 一方面,它們是值類型,如上面的int, double, boolean
[所以不應該產生開銷]但另一方面它們間接地從System.Object
派生,因此(技術上)應該產生開銷。
在您的應用程序中放置自定義結構類型的位置在哪里?
它們與原始類型沒有什么不同。 除了他們擁有的領域之外,它們不會帶來額外的開銷。 它們從object
派生的事實並不意味着它們會產生引用類型攜帶的開銷,即方法表指針和同步根塊。
你可以使用Marshal.SizeOf
來測試它:
void Main()
{
var f = new Foo();
Console.WriteLine(Marshal.SizeOf(f));
}
public struct Foo
{
public int X { get; set; }
public int Y { get; set; }
}
這將以32位模式打印8,這正好是兩個整數值(每個4個字節)。
注意Marshal.SizeOf
將輸出非托管對象的大小。 CLR仍然可以自由地重新排序字段或將它們打包在一起。
結構的大小由其字段大小的總和加上正確對齊的字段之間的填充,加上結構末尾的填充,確保在結構存儲時它們仍然正確對齊數組。
因此,對於一個,結構並不完全不可能包含引用類型的字段。 像一個字符串。 在這種情況下,結構將變得更大,因為引用是引擎蓋下的指針,占用8個字節而不是4個字節。
襯墊是更加狡猾的細節。 在32位模式下,變量不能指向優於4的對齊。 double
和long
,8字節類型的問題很容易被錯誤對齊。 特別是影響32位程序的性能,如果雙重在L1高速緩存邊界線上未對齊,則讀取或寫入速度可能是3倍。 這也是C#內存模型中這些類型不是原子的核心原因。 在64位模式下不是問題,然后CLR必須並確實提供8的對齊保證。
然而,CLR確實試圖在32位模式下給這樣的結構成員正確對齊,即使結構本身不能保證對齊。 否則,結構的副作用具有隱式[StructLayout(LayoutKind.Sequential, Pack=8)]
屬性。 CLR源代碼中的一個奇怪的是,執行此操作的C ++語句沒有注釋。 我懷疑它是一個快速修復不到恆星非托管互操作性能 ,保持結構blittable對速度非常重要。
然而,如果結構包含一個本身就是沒有順序布局的結構的成員,那么CLR就會放棄。 值得注意的是,這發生在DateTime
和DateTimeOffset
,編寫它們的程序員在其上應用[StructLayout(LayoutKind.Auto)]屬性是出於非常神秘的原因。 在DateTimeOffset的情況下可能是復制/粘貼錯誤。 結構的布局現在將是不可預測的,它也變為LayoutKind.Auto,CLR重新排列字段以最小化結構大小。 這可能會導致x64模式下的額外填充。
這些是不應該擔心的模糊實現細節。
字段的對齊可能會有一些開銷:
例如
public struct Test {
public Byte A;
public long B;
}
將大小在64位處理16個字節和12個字節在32位過程相應地(當我們可以預期只有9個字節);
零。
除非由於對齊而存在間隙,否則這就是這些差距的成本。
但是否則結構就像字段是在堆棧上布局的單獨變量一樣。
雖然它是盒子,你通過object
處理它,它具有與任何其他引用類型相同的開銷。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.