【编译】StreamInsight应用调优入门(四)——解析StreamInsight应用程序内存消耗

参考博客:http://blogs.msdn.com/b/domain_connect4


本文介绍将主要包括三个方面:首先会介绍一个StreamInsight应用消耗内存的场景,接下去会介绍与StreamInsight应用消耗内存相关的一些术语,最后会以一个实际案例为例进行分析结束本文。

应用场景

若假定StreamInsight应用程序是机器上唯一在运行的进程,那么所有可供其使用的内存将取决于“该进程所在的物理硬件与操作系统所提供的委托上限(Commit limit)”。这里委托上限是指物理内存与页面文件大小的总和。在真实情况下,并不是所有的物理内存都会被算作委托上限,因为操作系统本身会预留部分物理内存以供自己使用。我们通常会把所有活跃进程使用的虚拟内存总量称为“当前认可用量(Current Commit Charge)”,且该值不会超过系统委托上限。一旦当前认可用量接近委托上限,虚拟内存分配就会失败。

观察当前认可用量委托上限的最简单的方法就是使用Process Explorer工具中的“System Information”窗口,如下图所示:

图1:使用Process Explorer查看内存使用情况

红色矩形标记的两处分别表示了当前认可用量和委托上限以及前者占后者的百分比。如果图中“Current”数值非常接近“Limit”,那么应用程序就面临着“Out of Memory(内存耗尽)”的问题。

当前认可用量包含了物理内存以及页面文件大小,然而有时候却很难精确计算出所有进程使用的页面文件大小。因此在对StreamInsight应用程序进行故障排除时,可以考虑添加性能计数器“Process<youapplicationname>\Private Bytes”来观察其是否到达了委托上限

StreamInsight内存消耗术语

前一篇文章中介绍的StreamInsight事件调试器诊断视图中,读者也许看到了其中有不少关于内存的参数,如“Events Memory Used(Bytes)”,“Index Memory Used(Bytes)”等等。诊断StreamInsight内存消耗的问题恰恰是需要观察这些参数的变化。MSDN上的《监视StreamInsight 服务器和查询》文章对诊断视图中的各个参数都有了一个基本介绍,读者可以先行阅读以下。本文这里会重点介绍与内存消耗相关的参数。

  • 系统中处于活动状态的所有事件使用的内存量 [cep:/server/EventManager]
All Events Memory 系统中处于活动状态的所有事件使用的内存量(字节)。

StreamInsight引擎在查询处理过程中,会在原生堆上为输入事件、中间事件和输出事件分配和解分配内存。

  • 索引内存
OperatorIndexMemory 运算符中索引结构占据的累积内存总量(字节),它主要存储运算符状态,例如它会存储运算符保存下来用以进行增量计算或输出校正的事件。
  • 流内存
StreamMemoryIncludingEvents 流及其中的所有事件使用的内存量(字节)。

这块内存主要是为内部流队列以及队列中事件而分配的,它与事件部分的[Event Memory]稍有重合,在多数情况下,流队列中的事件总数都比较少。

  • 托管堆

不仅仅只有StreamInsight查询管理器会在托管堆中申请内存,输入/输出适配器也同样如此。读者可以通过使用性能计数器 [.NET CLR Memory\#Bytes in all heaps]来查看进程使用的堆内存总量。

案例分析:StreamInsight应用程序报告内存耗尽(OOM)异常该怎么办?

相信读者从上面的介绍中已经知道了不少种方法来查看某个进程的内存使用情况,下面我们会从一个案例出来来深入进行分析。这个案例其实并不少见,就是在StreamInsight应用程序运行过程中的某个时刻,会报告“Out of Memory(内存泄露,简称OOM)”。

为了让以下说明清晰易懂,我们假定机器上只有StreamInsight应用在运行,并且只有一个StreamInsight查询处于运行状态。

对StreamInsight应用程序内存问题进行故障排查时,比较好的做法是依次查看内存整体使用情况以及各个部分内存使用情况。下面将分别详细进行介绍:

查看内存总体使用情况

进程使用的内存总量可以通过性能计数器[Process\Private Bytes]观察到,该值显示了该进程所拥有的所有不与其他进程共享的内存量。这些内存包含了所有的代码,托管数据和非托管数据。

查看内存具体使用情况

通过查看以下特定的条目可以知道进程使用的内存分别用在了哪里:

  • 原生内存使用情况 --- 通过查看StreamInsight诊断视图获得
    • A = OperatorIndexMemory
      • 在查询诊断视图中查询以下地址的值获得:[“cep:/Server/Application/<appname>/Query/<queryname>”]
    • B = AllEventsMemory
      • 在查询诊断视图中查询以下地址的值获得:[“cep:/Server/EventManager”]
    • C = StreamMemoryIncludingEvents
      • 在查询诊断视图中查询以下地址的值获得:[cep:/Server/Application/<appname>/Query/<queryname>”]
  • 托管内存使用情况
    • D = All managed memory consumption
      • 查看性能计数器[.NET CLR Memory \#Bytes in all Heaps]的值获得托管内存使用情况。使用Windows自带的性能监视器Perfmon添加对应实例的计数器即可。

通常情况下,性能计数器[Process\Private Bytes]中查看到的值会比上述原生内存与托管内存使用的和还要略高,这是因为应用中可能有还有其他部分的开销或者存在一些没有被其他进程共享的代码段。

我们另内存总使用量E = A + B + C + D,那么下面的图片分别显示了各个参数在波峰位置的使用状况: 23GB(A) + 13GB(B) + 23MB (C) + 27GB(D) ~= 66GB(E)。可以看到[Process\Private Bytes]中的波峰值约为67G,要比上述综合略高。

图2:查询期间的运算符索引内存使用图,波峰值为23GB (A)

图3:查询期间的事件总内存使用图,波峰值为13GB(B)

图4:查询期间堆内存使用总量图,波峰值为27GB(C)

图5:查询期间进程使用内存总量图,波峰值为67GB(E)

上述5个内存使用值中,(A), (B), (D)和(E)是需要重点关注的对象。在对StreamInsight应用进行内存故障跟踪时,(C)常常显得并不那么重要,因为它的内存占用量相比其他4个因素要小得多,因此大部分情况下都会将其忽略掉。

 

至此,StreamInsight应用调优入门系列结束,感谢大家阅读,祝调优之路一路顺风!

posted @ 2011-11-30 18:27  StreamInsight  阅读(904)  评论(1编辑  收藏  举报