.NET集合和大对象堆(LOH)

11

在.NET中,如果集合中的项目数量很大,它们是否容易被存储在LOH(大对象堆)中?

我对List和Dictionary特别感兴趣。在我的代码中,我将大量(40k+)相对较小的对象(假设为1k)存储在临时列表和字典中进行处理。这些集合中的项目数量是否增加了放入LOH的可能性?

对于List来说,假设List是作为双向链表实现的,那么元素数量不应该增加实际List对象的大小,但我想确切知道。

谢谢!

4个回答

14

只有当对象大小超过85,000字节时,它们才会存储在LOH上。一个大的列表(特别是由结构体组成的列表)通常会被分配到这里。

然而,字典不太可能存储在LOH上,因为它们存储了一系列桶(bucket)的数组。除非生成足够多的桶使得数组大于85000字节,否则不太可能出现。即使是40k元素的类列表(因为每个元素中的对象引用将导致该列表在x86系统上达到160k,在x64系统上达到320k),也将存储在LOH上。但是每个单独的元素仍然会在标准堆(standard heap)上,因此会被压缩等处理。

如果使用双向链表而不是标准列表(List),则它很少存储在LOH上。列表的每个元素都很小(只是一个带有对下一个/上一个节点的引用的单个节点),因此没有单个对象大于85k字节。

有关LOH的详细信息,这篇博客文章讲得很好。


双精度数组有一个下限,因为它们在8字节边界上联合时速度更快(同样适用于List<double>,因为它使用了一个数组)。 - Ian Ringrose
2
字典的实现是作为一个合并哈希表(使用链式法,但使用数组来存储链接的桶,以获得一些开放地址法在缓存使用方面的优势),因此对于40k,它们将包含一个内部数组,大小为40000 *(keysize + valuesize + 8 [一个int来记忆哈希码和一个用于存储链中下一个索引的int])和一个内部数组,大小为40000 * 4(int大小)。那个40000实际上至少会达到43627,也可能达到90523,这取决于增长历史,因为它使用预计算的质数。因此,肯定会有... - Jon Hanna
1
至少需要一个436270字节的数组(如果键和值都是字节大小,则需要更多,对于任何其他大小也是如此),以及至少一个174508字节的索引数组。因此,一个40k元素的字典在LOH中始终会有一些内部表示(字典本身更像是40-80字节,在其中一个分代堆中,无论大小如何)。 - Jon Hanna
回应Jon所说的话,在我的经验中,字典是使用LOH和导致内存碎片化的最大罪犯之一。 - ToolmakerSteve
一些链表的实现并不会单独分配每个节点,而是使用结构体数组。链接不是引用,而是数组的索引。这样可以减少分配成本和GC处理的对象数量,即为GC节省工作量。对于这种实现,这个问题仍然存在。标准的LinkedList<T>不是这些实现之一。 - Palec

4

System.Collections.Generic.List 是以数组形式实现的,而不是链表。如果集合的大小较大,则会分配到大对象堆(请注意,数组的大小很重要,如果您有一个大型引用类型的小数组,则不会分配到 LOH)。


4

List被实现为一个数组。因此,该数组将被放入LOH中,但List对象本身不会。

同样地,Dictionary也是这样。它也在内部使用桶的数组,这些桶基本上存储您添加的键/值对。


0

字典具有O(LOG N)向量用于键/值,因此在40K+对象中您非常安全。 如前所述,列表被实现为数组,因此大型列表确实位于LOH上。 您可以使用SOS检查对象是否在LOH上


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接