所以我只是在测试微软的CLR Profiler,我做了一个小程序,创建了一个包含1,000,000双打的List。我检查了堆,结果列出了<>大小约为124KB(我不记得确切,但它就在那附近)。这真的震撼了我的世界,如果它有100万双打怎么可能是124KB呢?无论如何,之后我决定检查双[1000000]。令我惊讶的是(不是因为这是我对List<> = P的预期),数组大小为7.6MB。巨大的差异!!
他们怎么会有所不同? List<>如何?管理它的项目是如此(令人难以置信)内存效率?我的意思是,它不像其他7.5 mb在其他地方,因为在我创建了100万双打之后,应用程序的大小大约增加了3或4 KB。
答案 0 :(得分:18)
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字节。这非常适合引用类型(Array
)的通常12字节开销和双倍的1,000,000乘8字节。最重要的是List<T>
为上面显示的字段增加了另外24个字节的开销。
结论:对于相同数量的元素,我没有看到List<double>
占用的空间少于double[]
的证据。
答案 1 :(得分:1)
请注意,List是动态增长的,通常每次达到内部缓冲区大小时都会增加一倍。因此,新列表最初会有4个元素数组,在添加前4个元素后,第5个元素将导致内部重新分配将缓冲区加倍(4 * 2)
。