1

我正在调查“传统”.NET 服务器应用程序在生产中引发 OutOfMemoryException 的事件。我的目的是解释通过性能监视器收集的数据的特定部分,并寻求一些关于如何继续前进的建议。让我从一个事实清单开始:

  1. 该过程已经运行了 20 多天,直到崩溃。
  2. 它崩溃是因为抛出了System.OutOfMemoryException类型的异常。
  3. 过去也发生过类似的事件。同样,应用程序崩溃需要很长时间
  4. 该进程已通过以下计数器通过性能监视器进行监视:# 所有堆中的字节数、% 处理器时间、专用字节数、工作集。
  5. 我们无法在生产环境中捕获任何内存转储,也无法重现它。

在第一个屏幕截图中,您可以看到计数器在 7 天内的整体行为。事情非常稳定。第二个屏幕截图显示了崩溃前后最后一分钟的行为。OutOfMemoryException 记录在3:13:49PM

7天行为 坠机前的最后一分钟

我的问题是: 1.工作集突然增加意味着什么?它总体稳定在 650 多 MB,并在 10 秒内攀升至 1.3GB。2.我应该专注于在崩溃之前找到触发OOM的东西,还是它可能是一个累积因素?如您所见,私有字节和所有堆上的字节非常稳定。

4

1 回答 1

1

这类问题极难诊断。很可能发生的事情不是触发行为的单一条件的结果,而是一组同时发生的条件。

以下是我们所知道的:

  1. 没有显示累积性问题: 如果问题是累积性的,我们预计会看到导致事件发生的 20 天期间的一些迹象。这并不意味着前面的操作可以忽略。触发行为的某些条件可能是预先安排的,并且更早开始。这是我们无法通过现有信息知道的事情。

  2. 堆是稳定 的:Private Bytes 度量告诉我们保留了多少内存(未触及,如 stephbu 建议的那样)。Bytes-in-all-Heaps 告诉我们当前根据内存管理器 (GC) 分配了多少保留内存。由于这两个都是稳定的,因此问题似乎不一定是内存泄漏。危险在于我们只有 10 秒的有趣数据,而且由于 GC 通常是相当被动的,因此不清楚这些统计数据的准确度(尤其是不稳定的工作集)。

  3. 工作集表明颠簸: 工作集告诉我们操作系统想要保持多少物理内存以确保合理的性能。不断增长的工作集表明抖动。不断增长的工作集通常与两件事相关联:

    • 增加分配率

    • 增加对象寿命(通常是暂时的)

    没有指出增加的对象寿命,因为堆没有显示增长。增加分配率是可能的,但对象仍然是短暂的(因为未指示泄漏)。

这些观察结果向我表明,一些罕见的事件(或一组事件)正在触发以下情况:

  • 高分配率

  • 中等大小的物体

  • 寿命不长

  • GC因此而颠簸

还有其他关于这些情况导致 OutOfMemoryExceptions 的报告。我不太确定它为什么会发生。如果您运行的是 32 位环境,那么一个可能的原因是地址空间的碎片。如果 GC 无法从操作系统获取连续页面,则可能会发生这种情况。

另一种可能性(我无法验证)是 GC 请求操作系统不要分页它正在处理的堆的部分。如果锁定页数变高,可能会导致内存不足。这个想法几乎完全是猜测,因为我对微软 GC 实现的内部了解不够。

我现在没有更好的解释,但如果有人能提供一个更好的解释,我肯定会想要一个更好的解释。

最后,您可能想要验证是否启用了合理的延迟模式。如果这是问题所在,我想我们会看到 Bytes-in-all-Heaps 的升级——所以它可能没问题。

附言

你能检查第二张图表中虚线表示的变量是什么吗?如果是处理器使用,则与抖动一致。随着更频繁地调入内容的需求增加,磁盘 IO 应该增加,并且(在某个点)处理器使用百分比应该下降,因为一切都在等待磁盘。这只是一个额外的细节——如果处理器的使用没有过度下降,抖动仍然是一种可能性。这是因为部分软件可能仍然表现出良好的局部性并能够取得进展。

于 2012-12-18T23:10:08.663 回答