触发gen2垃圾收集的原因是什么?

Jef*_*ron 21 .net garbage-collection memory-management c#-4.0

我有一个奇怪的情况,我想弄明白.

创世纪:

我在具有16个内核和128GB RAM 的物理机器上运行我的程序.我试图确定为什么它没有使用所有可用的内核,通常它平均使用20-25%的CPU(因此16个中的4-5个内核).当我查看性能计数器时,它们显示垃圾收集时间为60-70%.

作为参考,我使用.NET Framework 4和TPL(Parallel.ForEach)来线程化程序中性能密集的部分.我将线程数限制为核心数.

问题:

我创建了大量的对象,对于垃圾收集器来说有太多的处理效率,因此它在垃圾收集器中花费了大量的时间.

到目前为止简单解决方案:

我正在引入对象池以减少垃圾收集器的压力.我将继续汇集对象以提高性能,已经将一些对象集中在一起,将垃圾收集从60-70%减少到45%的时间,我的程序运行速度提高了40%.

唠叨问题(我希望你能回答我的问题):

运行时我的程序使用最多14GB的可用RAM,而128GB的RAM则相当小.这台机器上没有其他东西在运行(它纯粹是我的测试台),并且有足够的RAM可用.

  • 如果有足够的RAM可用,为什么要发生任何gen2(或完整)集合呢?相当多的这些gen2集合(成千上万)正在发生.即如何确定启动gen2集合的阈值?
  • 为什么垃圾收集器不会简单地延迟任何完整的收集,直到物理RAM上的压力达到更高的阈值?
  • 有什么办法可以配置垃圾收集器等待更高的阈值吗?(即如果没有必要,根本不打扰收集)

编辑:

我已经在使用服务器垃圾收集器的选项...我需要知道的是什么是触发gen2集合,而不是服务器垃圾收集器更好(我已经知道).

Jim*_*hel 19

我记得,客户端GC是默认值.我的经验是它在收集之前不会让堆变得非常大.对于我的重型处理应用程序,我使用"服务器"GC.

您在应用程序配置文件中启用了服务器GC:

<?xml version ="1.0"?>
<configuration>
  <runtime>
    <gcServer enabled="true"/>
  </runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)

这对我来说在性能上有很大的不同.例如,我的一个程序花费了超过80%的时间用于垃圾收集.启用服务器GC将其降低到略高于10%.内存使用量上升是因为GC让它发挥作用,但这对我的大多数应用程序来说都很好.

导致Gen 2集合的另一件事是大对象堆.请参阅CLR Inside Out:大对象堆未覆盖.简而言之,如果超过LOH阈值,它将触发Gen 2集合.如果你要分配很多短寿命的大对象(大约85千字节),这将是一个问题.

  • 哇!我显然非常愚蠢.我的程序中有<gcserver enabled ="true">而不是<gcServer enabled ="true">.显然,它区分大小写!> - (我做了改变,看到性能提高了近10倍.%GC的时间平均从45%上升到12.5%.我仍然会回去继续汇集对象来挤出更多性能但没有你的注释我从来没有想过要回去检查垃圾收集器实际上是否设置为服务器.再次感谢! (5认同)

Nia*_*ton 5

从模糊的内存和阅读:http://msdn.microsoft.com/en-us/library/ee787088.aspx,我认为Gen 2 GC的一个触发器可以是第2代段填充.文章指出Server GC使用更大的段,如前所述,这可能对您的性能很重要.

让机器等到几乎没有任何无内存将意味着你在某个阶段得到一个地狱的GC.这可能不太理想.如果您在GC中的时间如此之高,那就表明您正在分配太多的物体,这些物体的存活时间足以超过第0和第1代,并以重复的方式进行.如果应用程序的内存使用量没有随着时间的推移而上升,则表明这些对象实际上是短暂的,但是活得足够长,可以在0和1集合中存活.这是一个糟糕的情况 - 您正在分配一个短期对象,但需要支付完整的第2代收集成本来清理它.

如果是这种情况,您可以采取以下几种不同的指示:

  1. 尽量让短寿命物品更快收集(因此它们不能生成第2代,因此GC成本更低)
  2. 尝试分配较少的短期对象(因此,在分配强制GC并将对象移动到较旧代之前,您可以更少地使用GC,并且您有更多时间来完成使用短期对象)
  3. 对于短期对象使用堆栈分配值类型而不是引用类型(如果它适合您的目的)
  4. 如果您知道需要大量这些对象,请将它们预先集中在一起.听起来你正在这样做,但仍然需要进行大量的分配以保持GC达到45%.如果您的游泳池不够大,请提前分配更多 - 正如您所说,您有足够的备用内存.

所有这些的组合可能是一个很好的解决方案.你需要很好地理解你分配的对象,他们的生活时间,以及他们实际需要多长时间来实现你的目的.

GC很满意具有较短寿命的临时对象(如可快速通过GC收集),或具有较长寿命的长期/永久性对象.在这两个类别的中间分配大量对象是你痛苦的地方.因此,分配较少的或更改其生命周期以匹配其使用方案.