【问题标题】:Garbage Collection in W3WP processW3WP 进程中的垃圾收集
【发布时间】:2015-10-29 07:30:09
【问题描述】:

调试我们的一台服务器使用的 CPU 比预期更多的性能问题我目前专注于 GC,因为 GC 中的 % 时间似乎在 30 左右,我觉得这太高了。

我还注意到一种模式,即 CPU 使用率缓慢上升,直到每晚午夜回收池。 LOH 的大小也逐渐增加(我怀疑这是因为我们缓存了用户信息),这让我认为 LOH 的增长是 CPU 的原因,而 GC 中的 % 正在逐渐增加,直到回收。我还注意到很多 gen2 集合。

看这张图有两件事让我印象深刻:

1) 这种 GC 模式正常吗?我认为第 2 代的收集次数要少得多。

2) 17:40 发生了什么?服务器有两个正在运行的应用程序池(一个只是一个虚拟网站,一个负责所有工作),对我来说,它们看起来像是在 17:40 切换位置,没有回收或似乎发生了任何事情。

GC 和 alloc B/sec 中的时间以一种奇怪但上升的模式跟随:

【问题讨论】:

  • GC 中的 % 是否也呈上升趋势?它隐藏在这里。
  • 因为 GC 中的时间似乎与这里的分配率密切相关。看起来完全健康。从图表中我看不到 LOH 大小的增加,但我接受你的工作。您可以分析应用程序并查看使用 CPU 的内容吗? PerfView 可以非侵入式地做到这一点。确保设置符号。
  • 我没有使用 PerfView 的经验,但我会尝试一下。感谢您的建议。

标签: .net debugging iis memory garbage-collection


【解决方案1】:

我不确定 17:40 发生了什么。

但是,这种模式对于 GC 来说是正常的。 Gen2 的收集次数会少很多,Gen0 的收集次数将多于 Gen1,Gen 1 的收集次数将多于 Gen 2。

简单介绍一下 GC 的工作原理。

对于托管对象,有 3 个小对象堆 (SOH) 和 1 个大对象堆 (LOH)。

大对象堆 (LOH)

大于 85KB 的对象会立即进入 LOH。如果您有太多大型对象,则会存在一些风险。这是一个不同的讨论,更多细节请查看The Dangers of the Large Object Heap

小对象堆(SOH):Gen0、Gen1、Gen2

垃圾收集器使用巧妙的算法仅在需要时执行垃圾收集器。完整的垃圾收集过程是一项昂贵的操作,不应该经常发生。因此,它已将其 SOH 分为三个部分,并且正如您所注意到的,每个 Gen 都有指定的内存量。

每个小对象 (

即使在下面执行时,实际上也会发生上述过程:(不需要手动调用)

// Perform a collection of generation 0 only.
GC.Collect(0);

通过这种方式,垃圾收集器首先清除为短期实例分配的内存(不可变的字符串、方法中的变量或更小的范围)。

当 GC 在一个阶段继续执行此操作时,Gen1 溢出。然后它对 Gen1 执行相同的操作。它会清除 Gen1 中所有不必要的内存,并将所有需要的内存复制到 Gen2。

上面的过程是当你手动执行下面的时候发生的(不需要手动调用)

// Perform a collection of all generations up to and including 1.
GC.Collect(1);

当 GC 在某一阶段继续执行此操作时,如果 Gen2 溢出,它会尝试清理 Gen2。

即使您手动执行以下操作也会发生上述过程(不需要手动执行)

// Perform a collection of all generations up to and including 2.
GC.Collect(2);

如果需要从 Gen1 复制到 Gen2 的内存量大于 Gen2 中可用的内存量,GC 会抛出内存不足异常。

【讨论】:

  • 谢谢,我知道 .NET 中的 GC 是如何工作的。当你写 gen 0 时应该收集很多,因为它成本低,gen 1 的次数更少,gen 2 的次数很少。正如 Tess 在这里建议的link 一个拇指规则是 gen 集合之间的比率为 100/10/1。我在这里看到的是 100/88/78 的比率,这意味着几乎所有集合都是完整集合。我需要有关如何解决此问题的指针....
  • 其实我已经调试这个问题一段时间了,我在我们的代码库中发现了几个地方调用了 GC.GetTotalMemory(true) 来进行性能日志记录,你可能知道这会触发完整的 gc 和因为该方法每分钟调用一次,这给 GC 带来了很大的压力,删除此代码有很大帮助,但 GC 仍在加班......
  • "这种模式对于 GC 来说是正常的" ???这是为什么?为什么这里的 CPU 会随着时间的推移而上升?
  • 在整个代码库中搜索 \bGB\b 作为正则表达式显示 GC.GetTotalMemory(false) 在一些地方被调用,但仅此而已,这不应该与 GC 混淆。除了在静态 GC 对象上调用方法和分配太多东西之外,还有其他方法可以弄乱 GC 吗?
最近更新 更多