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 ,和更专业的内存使用分析工具判断应用内存的使用情况。
 
原文地址:https://www.cnblogs.com/hbt19860104/p/2626637.html