亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

.NET陣列的開銷?

.NET陣列的開銷?

ibeautiful 2019-11-29 14:23:02
我試圖使用以下代碼確定.NET數組(在32位進程中)標頭的開銷:long bytes1 = GC.GetTotalMemory(false);object[] array = new object[10000];    for (int i = 0; i < 10000; i++)        array[i] = new int[1];long bytes2 = GC.GetTotalMemory(false);array[0] = null; // ensure no garbage collection before this pointConsole.WriteLine(bytes2 - bytes1);// Calculate array overhead in bytes by subtracting the size of // the array elements (40000 for object[10000] and 4 for each // array), and dividing by the number of arrays (10001)Console.WriteLine("Array overhead: {0:0.000}",                   ((double)(bytes2 - bytes1) - 40000) / 10001 - 4);Console.Write("Press any key to continue...");Console.ReadKey();結果是    204800    Array overhead: 12.478在32位進程中,object [1]的大小應與int [1]相同,但是實際上開銷跳升了3.28個字節,    237568    Array overhead: 15.755有人知道為什么嗎?(順便說一句,如果有人好奇的話,非數組對象(例如,上面循環中的(object)i)的開銷約為8個字節(8.384)。我聽說在64位進程中為16個字節。)
查看完整描述

3 回答

?
神不在的星期二

TA貢獻1963條經驗 獲得超6個贊

數組是引用類型。所有引用類型都帶有兩個附加的單詞字段。類型引用和SyncBlock索引字段,除其他外,這些字段用于實現CLR中的鎖定。因此,引用類型的類型開銷是32位上的8個字節。最重要的是,數組本身還存儲了另外4個字節的長度。這使總開銷達到12個字節。


我剛剛從喬恩·斯凱特(Jon Skeet)的答案中學到,引用類型的數組還有4個字節的額外開銷??梢允褂肳inDbg確認。事實證明,附加字是存儲在數組中的類型的另一個類型引用。所有引用類型的數組都在內部存儲為object[],并附加了對實際類型的類型對象的引用。因此,a string[]實際上只是一個object[]帶有對type的附加類型引用的a string。有關詳細信息,請參見下文。


存儲在數組中的值:引用類型的數組保存對對象的引用,因此數組中的每個條目都是引用的大?。?2位為4字節)。值類型的數組內聯存儲值,因此每個元素都將占用所討論類型的大小。


這個問題可能也很有趣:C#List <double> size vs double [] size


血腥細節


考慮以下代碼


var strings = new string[1];

var ints = new int[1];


strings[0] = "hello world";

ints[0] = 42;

附加WinDbg顯示以下內容:


首先,讓我們看一下值類型數組。


0:000> !dumparray -details 017e2acc 

Name: System.Int32[]

MethodTable: 63b9aa40

EEClass: 6395b4d4

Size: 16(0x10) bytes

Array: Rank 1, Number of elements 1, Type Int32

Element Methodtable: 63b9aaf0

[0] 017e2ad4

    Name: System.Int32

    MethodTable 63b9aaf0

    EEClass: 6395b548

    Size: 12(0xc) bytes

     (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

    Fields:

          MT    Field   Offset                 Type VT     Attr    Value Name

    63b9aaf0  40003f0        0         System.Int32  1 instance       42 m_value <=== Our value


0:000> !objsize 017e2acc 

sizeof(017e2acc) =           16 (        0x10) bytes (System.Int32[])


0:000> dd 017e2acc -0x4

017e2ac8  00000000 63b9aa40 00000001 0000002a <=== That's the value

首先,我們轉儲數組和值為42的一個元素??梢钥闯觯笮?6個字節。也就是說,int32值本身為4個字節,常規引用類型的開銷為8個字節,數組的長度為另外4個字節。


原始轉儲顯示SyncBlock,方法表int[],長度和值42(十六進制2a)。請注意,SyncBlock位于對象引用的前面。


接下來,讓我們看一下,string[]找出附加詞的用途。


0:000> !dumparray -details 017e2ab8 

Name: System.String[]

MethodTable: 63b74ed0

EEClass: 6395a8a0

Size: 20(0x14) bytes

Array: Rank 1, Number of elements 1, Type CLASS

Element Methodtable: 63b988a4

[0] 017e2a90

    Name: System.String

    MethodTable: 63b988a4

    EEClass: 6395a498

    Size: 40(0x28) bytes <=== Size of the string

     (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

    String:     hello world    

    Fields:

          MT    Field   Offset                 Type VT     Attr    Value Name

    63b9aaf0  4000096        4         System.Int32  1 instance       12 m_arrayLength

    63b9aaf0  4000097        8         System.Int32  1 instance       11 m_stringLength

    63b99584  4000098        c          System.Char  1 instance       68 m_firstChar

    63b988a4  4000099       10        System.String  0   shared   static Empty

    >> Domain:Value  00226438:017e1198 <<

    63b994d4  400009a       14        System.Char[]  0   shared   static WhitespaceChars

    >> Domain:Value  00226438:017e1760 <<


0:000> !objsize 017e2ab8 

sizeof(017e2ab8) =           60 (        0x3c) bytes (System.Object[]) <=== Notice the underlying type of the string[]


0:000> dd 017e2ab8 -0x4

017e2ab4  00000000 63b74ed0 00000001 63b988a4 <=== Method table for string

017e2ac4  017e2a90 <=== Address of the string in memory


0:000> !dumpmt 63b988a4

EEClass: 6395a498

Module: 63931000

Name: System.String

mdToken: 02000024  (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

BaseSize: 0x10

ComponentSize: 0x2

Number of IFaces in IFaceMap: 7

Slots in VTable: 196

首先,我們轉儲數組和字符串。接下來,我們轉儲的大小string[]。請注意,WinDbg在System.Object[]此處列出了類型。在這種情況下,對象大小包括字符串本身,因此總大小是數組中的20加上字符串的40。


通過轉儲實例的原始字節,我們可以看到以下內容:首先是SyncBlock,然后是的方法表object[],然后是數組的長度。之后,我們通過引用方法表找到了另外的4個字節。如上所示,可以通過dumpmt命令對此進行驗證。最后,我們找到對實際字符串實例的單個引用。


結論


數組的開銷可以按如下方式分解(即32位)


4字節的SyncBlock

數組本身的方法表(類型引用)為4個字節

數組長度為4個字節

引用類型的數組又添加了4個字節來保存實際元素類型的方法表(引用類型的數組位于內部object[])

即,對于值類型數組,開銷是12個字節,對于引用類型數組,開銷是16個字節。


查看完整回答
反對 回復 2019-11-29
?
達令說

TA貢獻1821條經驗 獲得超6個贊

我們有一個項目,可處理大量數據(最大2GB)。作為主要存儲,我們使用Dictionary<T,T>。實際上創建了數千個字典。將其更改List<T>為鍵和List<T>值(我們IDictionary<T,T>自己實現)后,內存使用量減少了約30-40%。



查看完整回答
反對 回復 2019-11-29
  • 3 回答
  • 0 關注
  • 446 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號