在OutOfMemoryException之前的WorkingSet Spike

时间:2012-12-13 18:47:34

标签: .net memory out-of-memory perfmon working-set

我正在研究一个事件,在这个事件中,对于“传统的”.NET服务器应用程序,已经在生产中抛出了OutOfMemoryException。我的目的是解释通过性能监视器收集的数据的特定部分,并就如何继续前进寻求一些建议。让我先从一系列事实开始:

  1. 此过程已在超过20天运行,直至崩溃。
  2. 它崩溃了,因为抛出了 System.OutOfMemoryException 类型的异常。
  3. 过去曾发生类似事件。同样,应用程序崩溃需要很长时间
  4. 此过程已通过以下计数器通过性能监视器进行监控:所有堆中的#字节数,处理器时间百分比,专用字节数,工作集。
  5. 我们无法捕获生产环境中的任何内存转储,但我们无法重现它。
  6. 在第一个屏幕截图中,您可以在7天的时间内查看计数器的整体行为。事情非常稳定。第二个屏幕截图显示了崩溃周围最后一分钟的行为。 OutOfMemoryException已记录在下午3:13:49

    7day behaviour Last minute around the crash

    我的问题是: 1.任何想法突然增加工作集是什么意思?整体稳定在650毫克MB,并在10秒内攀升至1,3GB。 2.我应该专注于在崩溃前找到触发OOM 的东西,还是累积因子?正如您所见,所有堆上的Private Bytes和Bytes都非常稳定。

1 个答案:

答案 0 :(得分:1)

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

以下是我们所知道的:

  1. 未显示累积问题:如果问题是累积的,我们预计会看到导致该事件发生前20天的一些迹象。这并不意味着可以忽略前面的操作。触发行为的某些条件可能会暂存,并在之前开始。这是我们无法通过现有信息了解的。

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

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

    • 提高分配率

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

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

  4. 这些观察结果告诉我,一些罕见的事件(或一组事件)正在触发一个条件:

    • 高分配率

    • 中等大小物件

    • 不是很长寿

    • GC正在吵架

    这些条件中有other reports导致OutOfMemoryExceptions。我不确定它为什么会发生。如果您正在运行32位环境,则可能的原因是地址空间碎片化。如果GC无法从操作系统获取连续页面,则会发生这种情况。

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

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

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

    <强> PS

    您可以查看第二张图表中虚线指示的变量吗?如果它是处理器使用,那么它与颠簸是一致的。随着对页面内容的需求更频繁地增加,磁盘IO应该增加,并且(在某一点)处理器使用百分比应该下降,因为一切都在等待磁盘。这只是一个额外的细节 - 如果处理器使用不会过度下降,颠簸仍然是一个可能性。这是因为软件的某些部分可能仍然具有良好的局部性并且能够取得进展。