【问题标题】:(Nearly) all garbage collections are full collections(几乎)所有垃圾回收都是完整回收
【发布时间】:2013-05-16 17:40:23
【问题描述】:

大约四天来,我一直在收集托管应用程序的性能计数器。在此期间,发生了以下垃圾回收:

  • 0 代:133,695
  • 第一代:133,413
  • 第二代:133,254

其中一些是使用GC.Collect() 的“诱导”完整集合。这四天有 323 人。

为什么我的所有(或基本上所有)收藏都是完整收藏?我猜这种情况会导致“% Time in GC”计数器非常高(超过 70%,即使分配的字节/秒显着下降)。

根据配置文件,注意我正在运行 .NET 4.0、64 位并使用服务器 GC,这可能很重要,也可能不重要。

【问题讨论】:

  • 我认为,我们必须更多地了解您的应用程序才能做出猜测。
  • 如果您调用 GC.Collect,您根本无法真正了解每个收集运行的频率;你在搞乱它想要做的事情。此外,GC 非常动态,因为它会在认为需要时运行集合,这意味着这将非常取决于您正在运行的代码以及您在什么范围内创建了多少内存,你坚持了多久,等等。
  • GC.Collect() 对所有世代进行了完整的收集。这绝对是一个促成因素。如果删除显式集合,请测试数字如何变化。除此之外,如果不知道您的应用程序的详细信息,我们也无话可说。
  • @Joel:如果您想了解更多信息,我很乐意提供帮助。你想知道什么?
  • @Servy:我非常怀疑每 16 分钟通过GC.Collect() 收集一个完整的集合对系统的影响很大。我可以删除它并验证它,但我非常怀疑。

标签: c# .net garbage-collection


【解决方案1】:

我正在分配大量内存(有时超过 300 MB/秒)

这足以解释您观察到的情况。这将在那一秒内触发大量收集,gen #0 和 gen #1 堆并没有那么大。这些代中的对象很有可能仍在使用中,因为它们刚刚被分配,所以第 0 代和第 1 代集合没有腾出足够的空间,几乎每个对象都被提升到第 2 代。 GC对此有一个对策,它会自动增加代大小。但这无法满足你对记忆的强烈渴望。您可以使用 Perfmon.exe 中的 .NET 内存性能计数器来观察这一点。任何 .NET 内存分析器都可以通过更漂亮的图表为您提供洞察力。

以如此高的速率分配内存并不容易,您必须分配大量数组。这本身就可以解释,大于 85,000 字节的数组分配在大对象堆中。寻找重用这些数组的方法。几乎所有 .NET 集合类都在底层使用数组。

【讨论】:

  • 我从第 0 代到第 1 代提升的字节/秒只有大约 32K,这似乎不是很高。我从第 1 代到第 2 代提升的字节/秒不到 4K。这似乎也不是很高。我正在运行服务器 GC,据我了解,这给了我更大的堆?
  • @Mark,您是否分配了大于 85,000 字节的数组或对象?如果是这种情况,那么您将绕过正常的分配方案并陷入所谓的Large Object Heap,这是一个被回收但从未压缩的特殊堆。这可能是您没有看到一代又一代的促销活动的原因。我认为 Hans 是正确的,垃圾收集器必须非常繁重才能跟上如此高的内存需求。 =)
  • @sgorozco:显然,我是。使用 PerfView,我为 GC 抓取数据,几乎每个集合(795 个中的 792 个)都是因为 AllocLarge。
  • @Mark:我认为按照 HansPassant 的建议(如果可能,重用不再需要的对象或数组)将具有强大的性能优势。祝你好运!
猜你喜欢
  • 1970-01-01
  • 2011-12-21
  • 2012-01-28
  • 2013-06-27
  • 2011-11-29
  • 2021-12-20
  • 2011-07-15
  • 2014-03-09
  • 2013-06-10
相关资源
最近更新 更多