aix内存泄露
介绍使用脚本判断内存泄漏的简便方法
Document #: 2811995H29001
Body:
[标题]
介绍使用脚本判断内存泄漏的简便方法
内容提要:
本文份四个部分介绍如何使用提供的脚本定位分析应用内存泄漏
一,前言
二,内存使用介绍
三,脚本使用介绍
四,示例分析
五,总结
说明:
介绍使用脚本判断内存泄漏的简便方法
一,前言
应用内存泄漏是UNIX 系统中比较常见的一种现象,如何定位并确定内存泄漏的
应用是一个相对复杂的过程。本文将探讨内存泄漏的产生,及在AIX 系统中如何利用
提供的脚本,在系统级层面判断内存泄漏的进程。
二,内存使用介绍
C 语言中,应用使用malloc() 函数从进程的堆栈中申请内存,而在C++ 中内存的申请
使用是在类的初始化中通过构造函数建立的,包含类及其成员。当进程不再需要部
分内存是,将通过系统free() 函数归还给操作系统,而在C++ 中则通过析构函数释放
类的内存。进程终止时,进程的使用的栈的内存将全部归还给操作系统。如果进程
申请使用的内存不能释放,而且进程堆栈持续增长,应用可能存在内存泄漏。最终
的结果是进程消耗所有的系统内存,导致应用异常终止,或者是系统启动自身的保
护机制杀掉进程,进而释放系统的内存。
操作系统开发者不断的探求如何更有效的使用、分配内存的策略,在AIX 4.2 –
5.2 版本中,使用Yorktown 机制分配系统内存,相对于以前的版本,AIX 5.3 中引入
了新的内存分配使用机制watson ,基于rbtree(red-black tree) 结构,提高了malloc 的
性能,同时减少了堆栈的碎片。
三,脚本使用介绍
本文提供一组脚本,通过这组脚本,可以比较简单、快速的判断定位,哪一个进程
产生内存泄漏。脚本名称post_vg.sh ,使用方法如下:
1) 首先搜集系统的初始状态,包含每个进程使用的内存情况:
# ps vg > ps.before
2) 间隔一段合适的时间后,如15 分钟,根据应用或系统的情况而定,重新收集系统的状态
# ps vg > ps.after
3) 比较系统的前后状态,判断进程的内存使用情况,输出信息中Delta 表明进程内存的前后
使用情况,如果值增加,其中一个可能的情况就是内存泄漏
# ./post_vg ps.before ps.after
脚本的内容如下:
#!/bin/ksh
#
#
# Correlate ps.before and ps.after data ..
#
# command output from ps vg
#
ONE_FILE=temp_ps_vg
print_help() {
print "Version 1.0"
print "Usage: post_vg.sh [single_file|before_ps after_ps]"
print " Post process ps vg output "
print " "
print " where, "
print " single_file contains a before and after snapshot"
print " "
print " No files specified - assume"
print " ==> ps_vg.before "
print " ==> ps_vg.after "
exit -1
}
main() {
if [[ $1 == "-?" ]]
then
print_help
exit -1
fi
if [[ $# == 2 ]]
then
cat $1 $2 > $ONE_FILE
elif [[ $# == 1 ]]
then
cat $1 > $ONE_FILE
else
cat ps_vg.before ps_vg.after > $ONE_FILE
fi
post_vg
rm $ONE_FILE
}
post_vg() {
cat $ONE_FILE | awk 'BEGIN {
list_label = "None"
}
/PID/ {
if( list_label == "None" )
list_label = "Before"
else
list_label = "After"
next
}
{
pid_list[$1]
pid_size[$1, list_label ] = $6
pid_name[$1] = $13
}
END {
printf("%15s\t%10s\t%11s\t%10s\t%10s\n", "pid", \
"Name", \
"Before Size", \
"After Size", \
"Delta")
for( pid in pid_list ) {
if( (pid,"Before") in pid_size && (pid,"After") in pid_size ) {
delta = pid_size[pid, "After"] - pid_size[pid, "Before"]
d_total += delta
printf("%15s\t%10s\t%11d\t%10d\t%10d\n", \
pid, \
pid_name[pid], \
pid_size[pid, "Before"], \
pid_size[pid, "After"], \
delta )
}
}
printf("*** Total Delta %d\n", d_total)
}'
}
main $@
四,示例分析
通过以下的简单应用,借助以上的脚本,分析系统内存的使用。
测使用例:
#include <stdio.h>
main() {
char *ptr;
int count=0;
/* 申请系统内存 */
for (count=0; count<100000; count++) {
ptr = (char *)malloc(1024*1024);
memset(ptr, 0, 1024*1024);
/* 释放系统内存,决定应用是否产生内存泄漏。如果生成内存泄漏的应用,需要打开注释 */
/* free(ptr);
*/
sleep(1);
}
}
编译链接以上程序,生成有内存泄漏和没有内存泄漏两种情况,应用名称如下:
memleak : 有内存泄漏
nmemleak :没有内存泄漏
测试如下:
1) 测试应用没有内存泄漏
a) 运行nmemleak程序
# nmemleak
b) 使用命令ps收集系统的状态
# ps vg >ps.before
c) nmemleak运行一段时间后,假定30秒,重新收集系统的状态
# ps vg >ps.after
d) 使用post_vg.sh分析状态文件,并查看Delta项是否为0
# ./post_vg.sh ps.before ps.after
输出结果如下:
pid Name Before Size After Size Delta
... ...
284 wait 40 40 0
192946 /usr/sbi 1300 1300 0
168240 nmemleak 1120 1120 0
119182 /usr/sbi 772 772 0
57792 /usr/sbi 640 640 0
... ...
*** Total Delta 0
从上面的分析结果可以看出,Delta项值为0,也就是说,可以基本断定nmemleak没有内存泄漏。
2) 测试应用有内存泄漏
a) 运行memleak程序
# memleak
b) 使用ps命令收集系统的初始状态
# ps vg >ps.before
c) memleak运行一段时间后,假定30秒,重新运行ps命令收集系统的状态
# ps vg >ps.after
d) 使用post_vg.sh分析状态文件,查看Delta项
# post_vg.sh ps.before ps.after
查卡分析结果如下:
pid Name Before Size After Size Delta
... ...
90456 /usr/ccs 128 128 0
110734 /usr/sbi 1520 1520 0
209368 telnetd 624 624 0
168274 memleak 13408 42080 28672
147862 /usr/sbi 212 212 0
36882 pilegc 144 144 0
115076 /usr/sbi 1040 1040 0
78120 rpc.lockd 204 204 0
284 wait 40 40 0
... ...
*** Total Delta 28672
分析以上结果,可以看到,memleak 应用使用的进程内存增加了28672K 字节,明显存在内存
泄漏。接下来,要做的是定位应用那个函数造成的内存泄漏,需要按行定位代码,或者使用
第三方的内存检测工具,如Purify 。
五,总结
决定于应用的复杂程度,确定和定位内存泄漏,难度会相应的不同,结合系统提供的其他工具,
如svmon ,和更专业的内存使用分析工具判断应用内存的使用情况。