我有一个奇怪的情况,我想弄清楚。
创世纪:
我在具有 16 内核和 128GB 内存的物理计算机上运行我的程序。我试图确定为什么它没有使用所有可用的内核,通常它平均使用20-25%的CPU(因此16个中的4-5个内核)。当我查看性能计数器时,它们显示垃圾收集时间为60-70%。
作为参考,我使用.NET Framework 4和TPL(Parallel.ForEach)来编写程序的性能密集型部分。我将线程数限制为核心数。
问题:
我正在创建大量对象,对于垃圾收集器来说有效处理太多,因此它在垃圾收集器中花费了大量时间。
到目前为止的简单解决方案:
我正在引入对象池以减少垃圾收集器的压力。我将继续汇集对象以提高性能,已经将一些对象集中在一起,将垃圾收集从60-70%减少到45%的时间,我的程序运行速度提高了40%。
唠叨问题(我希望你能回答我的问题):
我的程序在运行时使用最多14GB的可用内存,相比之下128GB的内存则非常小。这台机器上没有其他东西在运行(它纯粹是我的测试台),并且有足够的RAM可用。
修改
我已经在使用服务器垃圾收集器了...我需要知道的是什么是触发gen2集合,而不是服务器垃圾收集器更好(我已经知道了)。
答案 0 :(得分:19)
我记得,客户端GC是默认值。我的经验是它在收集之前不会让堆变得非常大。对于我的重型处理应用程序,我使用“服务器”GC。
在应用程序配置文件中启用服务器GC:
<?xml version ="1.0"?>
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
这对我来说在性能方面存在巨大的差异。例如,我的一个程序花费了超过80%的时间用于垃圾收集。启用服务器GC将其降低到略高于10%。内存使用量上升是因为GC让它发挥作用,但这对我的大多数应用程序来说都很好。
将导致Gen 2集合的另一件事是大对象堆。见CLR Inside Out: Large Object Heap Uncovered。简而言之,如果超过LOH阈值,它将触发Gen 2集合。如果你要分配很多短寿命大对象(大约85千字节),这将是一个问题。
答案 1 :(得分:5)
从模糊的记忆和阅读:http://msdn.microsoft.com/en-us/library/ee787088.aspx,我认为Gen 2 GC的一个触发器可以是第2代段填充。文章指出Server GC使用更大的段,如前所述,这可能对您的性能很重要。
让机器等到它几乎没有任何无内存将意味着你在某个阶段得到一个地狱的GC。这可能不太理想。如果您在GC中的时间如此之高,那就表明您正在分配太多的物体,这些物体的存活时间足以超过第0代和第5代。 1,并以重复的方式进行。如果应用程序的内存使用量没有随着时间的推移而上升,则表明这些对象实际上是短暂的,但是活得足够长,可以在0和1集合中存活。这是一个糟糕的情况 - 您正在分配一个短期对象,但需要支付完整的第2代收集成本来清理它。
如果是这种情况,您可以采取一些不同的指示:
所有这些的组合可能是一个很好的解决方案。你需要很好地理解你分配的对象,他们的生活时间,以及他们实际需要多长时间来实现你的目的。
GC对生命周期较短的临时对象(如GC可快速收集)或长期/永久性对象的生命周期很满意。在这两个类别的中间分配大量对象是你痛苦的地方。因此,分配较少的或更改其生命周期以匹配其使用场景。