我已经阅读了有关“世代”和“大对象堆”的信息。但是我仍然不明白拥有大对象堆的意义(或好处)是什么?
如果CLR仅依赖第2代(考虑到Gen0和Gen1的阈值很小,无法处理大对象)来存储大对象,那可能会出错(在性能或内存方面)?
我已经阅读了有关“世代”和“大对象堆”的信息。但是我仍然不明白拥有大对象堆的意义(或好处)是什么?
如果CLR仅依赖第2代(考虑到Gen0和Gen1的阈值很小,无法处理大对象)来存储大对象,那可能会出错(在性能或内存方面)?
Answers:
垃圾回收不仅摆脱了未引用的对象,而且还压缩了堆。这是非常重要的优化。它不仅使内存使用效率更高(没有未使用的漏洞),而且使CPU缓存效率更高。高速缓存在现代处理器上确实非常重要,它们比内存总线快一个数量级。
压缩仅通过复制字节即可完成。但是,这需要时间。对象越大,复制它的成本越有可能超过可能的CPU缓存使用率改进。
因此,他们运行了一系列基准来确定收支平衡点。达到85,000字节作为截止点,复制不再能改善性能。除了double数组的特殊例外,当数组具有1000个以上的元素时,它们被视为“大”数组。这是对32位代码的另一种优化,大对象堆分配器具有特殊的属性,即它在对齐8的地址上分配内存,这与常规世代分配器只分配对齐4的地址不同。 ,读取或写入未对齐的double十分昂贵。奇怪的是,稀疏的Microsoft信息从未提及过很长的数组,不确定这是怎么回事。
Fwiw,关于大型对象堆没有压缩的很多程序员的担忧。当他们编写的程序占用了整个可用地址空间的一半以上时,就会始终触发此操作。然后使用诸如内存探查器之类的工具来找出为什么程序轰炸的原因,即使仍有大量未使用的虚拟内存可用。这样的工具可以显示LOH中的漏洞,即以前未使用的大块内存在其中的大型对象居住但被收集到的垃圾。这就是LOH的必然价格,只能通过分配大小相等或较小的对象来重复使用该孔。真正的问题是假设应允许程序在任何时间消耗所有虚拟内存。
通过仅在64位操作系统上运行代码,该问题可以完全消失。64位进程具有8 TB的虚拟内存地址空间可用,比32位进程大3个数量级。您就是不会洞洞。
长话短说,LOH使代码运行更有效率。以使用可用虚拟内存地址空间的效率较低为代价。
UPDATE.NET 4.5.1现在支持压缩LOH GCSettings.LargeObjectHeapCompactionMode属性。请当心后果。
小对象堆(SOH)和大对象堆(LOH)的本质区别在于,如本文所述,SOH中的内存在收集时会压缩,而LOH不会。压缩大型对象的成本很高。与本文中的示例类似,假设在内存中移动一个字节需要2个周期,然后在2GHz的计算机中压缩8MB的对象需要8ms,这是很大的成本。考虑到大对象(在大多数情况下为数组)在实践中很常见,我想这就是Microsoft将大对象固定在内存中并提出LOH的原因。
顺便说一句,根据这篇文章,LOH通常不会产生内存碎片问题。
原理是,进程不太可能(并且很可能是错误的设计)会创建大量短寿命的大对象,因此CLR将大对象分配给单独的堆,并在该堆上按与常规堆不同的时间表运行GC。http://msdn.microsoft.com/zh-CN/magazine/cc534993.aspx