C# 列表大小与双[]大小

发布于 2024-08-05 23:47:43 字数 517 浏览 2 评论 0原文

所以我只是在测试 来自微软的 CLR Profiler,我做了一个小程序,创建了一个包含 1,000,000 个双精度数的列表。我检查了堆,发现 List<>大小约为 124KB(我记不太清了,但大约是这个值)。这真的震撼了我的世界,如果它有 100 万个双精度数,它怎么可能是 124KB?无论如何,之后我决定检查 double[1000000]。令我惊讶的是(其实也不是,因为这是我对 List<> =P 的预期),数组大小为 7.6MB。巨大的差异!

他们怎么不一样?列表如何<>管理其项目,使其内存效率如此(令人难以置信)?我的意思是,这不像其他 7.5 mb 在其他地方,因为在我创建 100 万个双打之后,应用程序的大小大约增加了 3 或 4 KB。

So I just was testing the CLR Profiler from microsoft, and I did a little program that created a List with 1,000,000 doubles in it. I checked the heap, and turns out the List<> size was around 124KB (I don't remember exactly, but it was around that). This really rocked my world, how could it be 124KB if it had 1 million doubles in it? Anyway, after that I decided to check a double[1000000]. And to my surprise (well not really since this is what I expected the with the List<> =P), the array size is 7.6MB. HUGE difference!!

How come they're different? How does the List<> manage its items that it's so (incredibly) memory efficient? I mean, it's not like the other 7.5 mb were somewhere else, because the size of the application was around 3 or 4 KB bigger after I created the 1 million doubles.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

栖竹 2024-08-12 23:47:43

List 使用数组来存储值/引用,因此我怀疑除了 List 添加的少量开销之外,大小上还会有任何差异。

下面的代码

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 是 8,000,036 字节,底层数组是 8,000,012 字节。这非常适合引用类型 (Array) 的通常 12 字节开销和双精度数的 1,000,000 乘以 8 字节。在 List 之上,为上面显示的字段添加了另外 24 字节的开销。

结论:对于相同数量的元素,我没有看到任何证据表明 List 占用的空间比 double[] 少。

List<T> uses an array to store values/references, so I doubt there there will be any difference in size apart from what little overhead List<T> adds.

Given the code below

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

the heap looks like this for the relevant object

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[])

So the List<double> is 8,000,036 bytes, and the underlying array is 8,000,012 bytes. This fits well with the usual 12 bytes overhead for a reference type (Array) and 1,000,000 times 8 bytes for the doubles. On top of that List<T> adds another 24 bytes of overhead for the fields shown above.

Conclusion: I don't see any evidence that List<double> will take up less space than double[] for the same number of elements.

久光 2024-08-12 23:47:43

请注意,列表是动态增长的,通常每次达到内部缓冲区大小时都会将大小加倍。因此,新列表最初将具有类似 4 元素数组的内容,在添加前 4 个元素后,第 5 个元素将导致内部重新分配,将缓冲区加倍到 (4 * 2)

Please note that the List is dynamically grown, usually doubling the size every time you hit the internal buffer size. Hence, the new list would have something like 4 element array initially, and after you add the first 4 elements, the 5th element would cause internal reallocation doubling the buffer to (4 * 2).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文