IBM Support

利用性能探测器分析内存泄漏

Technical Blog Post


Abstract

利用性能探测器分析内存泄漏

Body

原址链接:http://www.ibmsystemsmag.com/ibmi/administrator/performance/Using-Performance-Explorer-for-Memory-Leak-Analysi/?page=1

 

在之前发表的文章“如何使用性能探测器的 *STATS*PROFILE/PGM功能”里面,我解释了性能探测器的*STATS*PROFILE数据集合类型,使用这两种集合类型可以非常便捷的进行数据收集,并能很容易的分析出CPU时间被哪些地方所使用。在这篇文章里,我将切换一下角度,去集中分析内存泄漏问题。内存泄漏是指那些在堆里分配的、但是无法被释放或者无法被重新分配的内存。这是在C/C++代码中很常见的问题,通常是由于程序员的疏忽,导致应用程序在进入某个异常甚至是正常的分支时没能正确的释放内存资源,程序员的技术水平决定了代码中是否有内存泄漏风险。

 

注意:这个讨论不适用于Java堆,因为Java从系统内存存储区创建自己的堆区,在Java堆区分配的内存空间最终将被垃圾回收器自动清理。

 

收集数据

 

为了能够收集到分析内存泄漏所需要的数据,必须要收集堆存储事件,其中包括系统堆、用户堆、常驻堆、本地堆、激活组堆、基于处理的堆以及C运行时堆(V5R3之后才支持的新功能)。要想收集到包括C运行时在内所有的这些事件,需要遵循以下步骤。

1. 给环境变量QYPE_ALLHEAP设置一个有效的值:

ADDENVVAR QYPE_ALLHEAP VALUE(ALL)

使用这个变量的原因是C运行时堆事件功能在发布到V5R3版本的时候,并没有对命令ADDPEXDFN做相应的修改。在未来版本(V6R1以后的版本)中,*CLEHEAP事件将会在ADDPEXDFN命令的STGEVT参数中被支持,因此就不需要再对这个环境变量进行设置了。

2. 现在使用ADDPEXDFN命令为堆事件添加定义。在参数中指定堆存储事件,上一步设置的环境变量将会使得所有的其他堆事件都被添加。

ADDPEXDFN DFN(HEAPTRC) TYPE(*TRACE) TRCTYPE(*SLTEVT) SLTEVT(*YES) STGEVT(*USRHEAP) JOB(*ALL) TASK(*ALL) MAXSTG(100000)

3. 删除之前设置的环境变量,这样可以避免以后你不经意当中创建一个包括了所有堆事件的定义。

 RMVENVVAR ENVVAR(QYPE_ALLHEAP)

4. V5R2版本不支持*CLEHEAP事件,所以你需要遵循下面的定义来指定所有V5R2支持的堆事件。

ADDPEXDFN DFN(HEAPTRC) TYPE(*TRACE) TRCTYPE(*SLTEVT) SLTEVT(*YES) STGEVT((*SYSHEAP) (*RESHEAP) (*LCLHEAP) (*USRHEAP) (*ACTGRPHEAP) (*HDLHEAP))  JOB(*ALL) TASK(*ALL) MAXSTG(100000) 

5. 现在有可以启动性能探测器的跟踪日志功能:

STRPEX SSNID(ALLHEAP) DFN(HEAPTRC)

这将使得性能探测器跟踪系统上所有作业以及任务的堆活动情况,直到收集的数据量达到100MB或者人为终止跟踪日志为止。

6. 使用下面的命令来结束跟踪日志程序:

ENDPEX SSNID(ALLHEAP)

查看数据

现在你可以使用堆的跟踪日志数据了。打印性能探测器报告命令(PRTPEXRPT)在性能工具包中是可用的,但是产生的报告可能非常庞大,从而不易于直接查看。所以你需要其他的工具帮你总结数据来回答例如下面的一系列问题:

1. 什么样的堆存储是处于分配状态的?

2. 有多少堆存储被分配了?

3. 哪些应用程序/模块/过程分配了堆存储,但是并没有释放掉这些堆存储?   

你想要使用的工具是性能跟踪日志可视化工具(PTDV)IBM i 系列的4.2 版本。关于这个工具的更多的信息可以在线查找到(http://www.alphaworks.ibm.com/tech/ptdv)。

在执行内存分配和解除分配时,每个堆事件包含10个级别的程序堆。PTDV可以发现所有的不匹配的分配和解除分配操作,然后总结这些对调用请况,然后以可视化形式展示出来,使使用者能够确认哪些程序或过程调用了这些分配操作。

遵循下面的步骤来使用PTDV工具:

1.  选择一个集合并开始分析。在这个例子中,我选择了MYSYSTEM系统上QPEXDATA目录中的ALLHEAP集合。我使用Thin Client(瘦客户端)选项卡,这会使得大部分的处理都在存放集合的IBM i系统上进行。选择“开始处理”来开始进行分析(看图1)。PTDV会提示你需要查看什么样的视图。

图像                                                              

 

 

 

 

 

 

                              

 

                                                                 1

2. 确保图2中的视图被选中。

图像

 

 

 

 

 

 

 

 

 

                                                                         2

3. 点击OK按钮后PTDV将会做分析处理。 你将会看到图3所示的面板。这个面板显示了集合的高层次信息,包括该集合的名称是ALLHEAP,存放在QPEXDATA目录。集合中包含了1337条独立的过程和方法调用,这些信息来源于集合数据中的调用堆栈信息。这个集合持续了219秒的时间,收集了15700个堆事件。总的悬挂时间是0秒,这意味着跟踪日志缓冲并没有被塞满。如果悬挂时间不为0,说明这个集合曾经暂停过,暂停和ENDPEX命令执行之间的时间就是悬挂时间。                                                           

图像

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                 图3  

4. 点击面板左上角Heap memory leak summary with caller information(包含调用者信息的堆内存泄漏概要)的选项卡。你将会看到图4所示,显示了所有类型的堆以及有多少是处于分配状态的(Total size not deleted(未清除的总大小) 列)

图像

 

 

 

 

 

 

 

 

 

                               图4

5. 如果你点击左边第一个ACTGRPHEAP行对应的旋钮,这行将会展开显示第一个栈级别的条目。如果你点击Total size not deleted(未清除的总大小)列中值最大的行,你最终会看到整个的10级堆栈,也可以判断出内存泄漏大多发生在哪里。你还可以点击Total size not deleted(未清除的总大小)列头对该列进行排序,因此所有展开的条目都会自动升到上面去(看图5)。

 

图像

 

 

                                                 

 

 

 

 

 

 

 

 

 

                              图5

在这个例子里,我们可以看到一个比较大的内存分配在第4级的QTENPTS/TERTCMD. InitializeCommandHistory调用处没有被清理掉。然而,这个可能是也可能不是一个问题。如果那个作业还仍然处于这个函数运行中的话就不能判定这是个问题,这种情况可能是由于我们只是简单的收集到内存释放之前的数据。但是,如果你已经知道那个分配内存的作业已经运行结束,并且你还知道分配的堆内存在集合数据被收集完成前就应该被释放掉,那么这个程序/过程应该是你需要调查的对象,去分析为什么没有去释放内存。

 

只有两种类型的堆可以在非操作系统应用程序中使用:

1)  *CLEHEAPILE C运行时堆)  当使用STGMDL(*TERASPACE)选项或者TERASPACE(*YES *TSIFC)选项编译C或者C++应用程序时,命名为CLEHEAP的堆被C运行时malloc/calloc/ realloc/free的常规调用所使用。在当前版本的PTDV工具里,这种堆还不能被识别,但是这个工具后续更新将会包含这一支持。

2) *ACTGRPHEAP(激活组堆)当程序编译后,不能使用CLEHEAP的时候可以使用这种堆类型。

 

其他的堆类型((*SYSHEAP *RESHEAP *LCLHEAP *HNDLHEAP 以及 *USRHEAP)被严格的限定为只能被操作系统所使用。如果你想减少跟踪日志集合的大小,而且只关注应用程序级别的堆,那么你可以在运行ADDPEXDFN的时候忽略这些堆类型。
  

协同工作

 

堆存储分析可以在生产机上进行,但是显然最好能在应用程序在部署之前就发现内存泄漏。利用性能探测器和PTDV协同工作,程序员可以快速而准确的鉴别内存泄漏问题,可以避免其将来成为一个客户报来的问题。

 

译者:张赜,孔祥坤

[{"Business Unit":{"code":"BU054","label":"Systems w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":""}]

UID

ibm11144954