Список C # <double>размер против двойного [] размера - PullRequest
5 голосов
/ 02 октября 2009

Итак, я только что тестировал CLR Profiler от Microsoft, и я создал небольшую программу, которая создала список с 1 000 000 двойников. Я проверил кучу, и оказалось, что размер List <> составлял около 124 КБ (точно не помню, но это было около того). Это действительно потрясло мой мир, как это могло быть 124KB, если бы в нем было 1 миллион двойников? Во всяком случае, после этого я решил проверить двойной [1000000]. И, к моему удивлению (ну, не совсем, так как это то, что я ожидал от List <> = P), размер массива составляет 7,6 МБ. ОГРОМНАЯ разница !!

Почему они разные? Как List <> управляет своими элементами так, что это (невероятно) эффективно использует память? Я имею в виду, это не так, как остальные 7,5 МБ были где-то еще, потому что размер приложения был примерно на 3 или 4 КБ больше после того, как я создал 1 миллион удваивается.

Ответы [ 2 ]

18 голосов
/ 02 октября 2009

List<T> использует массив для хранения значений / ссылок, поэтому я сомневаюсь, что там будет какая-то разница в размере, кроме того, что добавляет List<T> небольшие накладные расходы.

Учитывая код ниже

var size = 1000000;
var numbers = new List<double>(size);
for (int i = 0; i < size; i++) {
   numbers.Add(0d);
}

куча выглядит так для соответствующего объекта

0:000> !dumpheap -type Generic.List  
 Address       MT     Size
01eb29a4 662ed948       24     
total 1 objects
Statistics:
      MT    Count    TotalSize Class Name
662ed948        1           24 System.Collections.Generic.List`1[[System.Double,  mscorlib]]
Total 1 objects

0:000> !objsize 01eb29a4    <=== Get the size of List<Double>
sizeof(01eb29a4) =      8000036 (    0x7a1224) bytes     (System.Collections.Generic.List`1[[System.Double, mscorlib]])

0:000> !do 01eb29a4 
Name: System.Collections.Generic.List`1[[System.Double, mscorlib]]
MethodTable: 662ed948
EEClass: 65ad84f8
Size: 24(0x18) bytes
 (C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
65cd1d28  40009d8        4      System.Double[]  0 instance 02eb3250 _items    <=== The array holding the data
65ccaaf0  40009d9        c         System.Int32  1 instance  1000000 _size
65ccaaf0  40009da       10         System.Int32  1 instance  1000000 _version
65cc84c0  40009db        8        System.Object  0 instance 00000000 _syncRoot
65cd1d28  40009dc        0      System.Double[]  0   shared   static _emptyArray
    >> Domain:Value dynamic statics NYI
 00505438:NotInit  <<

0:000> !objsize 02eb3250 <=== Get the size of the array holding the data
sizeof(02eb3250) =      8000012 (    0x7a120c) bytes (System.Double[])

Таким образом, List<double> составляет 8 000 036 байт, а базовый массив - 8 000 012 байт. Это хорошо согласуется с обычными 12-байтовыми издержками для ссылочного типа (Array) и 1 000 000 × 8 байт для двойников. Вдобавок к этому List<T> добавляет еще 24 байта служебных данных для полей, показанных выше.

Заключение : Я не вижу никаких доказательств того, что List<double> займет меньше места, чем double[] для того же числа элементов.

1 голос
/ 02 октября 2009

Обратите внимание, что список динамически увеличивается, обычно удваивая размер каждый раз, когда вы достигаете размера внутреннего буфера. Следовательно, новый список изначально будет иметь что-то вроде 4-элементного массива, и после добавления первых 4-х элементов 5-й элемент вызовет внутреннее перераспределение, удваивающее буфер до (4 * 2).

...