Linux檢測記憶體洩露的指令碼
1.針對應用場景下的記憶體洩露
#!/bin/sh if [ $# -ne 1 ]; then echo "Usage: `basename $0` process_name" exit 1 fi APPNAME=$1 PROC="`ps -ef | grep "$APPNAME" | grep -v "grep" | grep -v "awk" | grep -v $0 | awk '{print $2}'`" if [ -z $PROC ]; then echo "invalid process_name" exit 1 fi SMAPS="/proc/$PROC/smaps" STATUS="/proc/$PROC/status" echo "proc ---$PROC----" OLDHEAP="0" while : do #HEAP="`cat $STATUS | grep "VmData" | awk '{print $2}'`" HEAP=`cat $SMAPS | grep -A 5 "heap" | grep "Rss" | awk '{print $2}'` if [ $HEAP -lt $OLDHEAP ]; then echo "`date` HEAP -`expr $OLDHEAP - $HEAP` to $HEAP kb" OLDHEAP=$HEAP elif [ $HEAP -gt $OLDHEAP ]; then echo "`date` HEAP +`expr $HEAP - $OLDHEAP` to $HEAP kb" OLDHEAP=$HEAP fi sleep 1 done
我們來個測試程式:
leak_demo.c
#include <stdio.h>
#include <unistd.h>
void main(void)
{
char* mm = NULL;
do{
mm = (char *)malloc(100);
memset(mm,0x0,100);
sleep(1);
}while(1);
}
我們先將leak_demo編譯後生成a.out,然後執行起來,之後執行指令碼
sh mm-leak-app.sh a.out
結果如下:
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 4 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 8 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 12 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 16 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 20 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 24 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 28 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 32 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 36 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 40 kb
2018年 10月 17日 星期三 17:16:48 CST HEAP +4 to 44 kb
我們發現指令碼是能夠檢測到程式的記憶體洩露的。
2.針對核心場景下的記憶體洩露
#!/bin/sh
# arg 1: sleep time(s)
if [ $# -ne 1 ]; then
echo "Usage: `basename $0` sleep_time(s)"
exit 1
fi
while (true)
do
mm=$(cat /proc/meminfo | grep "Slab" | awk '{print $2}')
echo $mm KB
sleep $1
done
如上我們實際上是統計的是/proc/meminfo 下面Slab的佔用的記憶體,我們需要特別注意一點,Slab只會統計核心通過kmalloc單次分配8KB以下的記憶體,如果單次通過kmalloc申請的記憶體在8KB以上的話,那麼在/proc/meminfo中的Slab是不會體現出來的,只會在free中有體現。測試demo如下:
static ssize_t workqueue_proc_store(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
int cnt = 0;
#ifdef MM_LEAK_DEBUG
do{
char *mm = kmalloc(1024, GFP_KERNEL);
printk("mem leak,ptr = %p\n",mm);
if(mm)
{
memset(mm,0x0,1024);
mm = kmalloc(1024, GFP_KERNEL);
printk("mem leak,ptr = %p\n",mm);
kfree(mm);
}
cnt++;
}while(cnt <= 1024);
#endif
return count;
}
3.測試Slab統計不到的核心記憶體洩露
測試指令碼如下:
cat /proc/buddyinfo | awk '{sum=0;for(i=5;i<=NF;i++) sum+=$i*(2^(i-5))};{total+=sum/256};{print $1 " " $2 " " $3 " " $4 "\t : " sum/256 "M"} END {print "total\t\t\t : " total "M"}'
指令碼實際上是統計的buddy剩餘的記憶體,檢視這個值在不斷減少也只能確定記憶體在洩露,無法確認是否是核心或者應用的洩露。
測試程式:
static ssize_t workqueue_proc_store(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
int cnt = 0;
#ifdef MM_LEAK_DEBUG
do{
char *mm = kmalloc(1024*1024, GFP_KERNEL);
printk("mem leak,ptr = %p\n",mm);
if(mm)
{
memset(mm,0x0,1024*1024);
mm = kmalloc(1024*1024, GFP_KERNEL);
printk("mem leak,ptr = %p\n",mm);
kfree(mm);
}
//cnt++;
break;
}while(cnt <= 1024);
#endif
return count;
}
核心中構造了一個缺陷,單次記憶體洩露1M,我們先看看Slab能否統計到
/ # cat /proc/meminfo | grep "Slab"
Slab: 18072 kB
/ # cat /proc/buddyinfo | awk '{sum=0;for(i=5;i<=NF;i++) sum+=$i*(2^(i-5))};{tot
al+=sum/256};{print $1 " " $2 " " $3 " " $4 "\t : " sum/256 "M"} END {print "tot
al\t\t\t : " total "M"}'
Node 0, zone Normal : 472.902M
total : 472.902M
/ # echo 1 > /proc/workqueue ---->記憶體洩露1M
mem leak,ptr = 9de00000
mem leak,ptr = 9df00000
/ #
/ #
/ # cat /proc/buddyinfo | awk '{sum=0;for(i=5;i<=NF;i++) sum+=$i*(2^(i-5))};{tot
al+=sum/256};{print $1 " " $2 " " $3 " " $4 "\t : " sum/256 "M"} END {print "tot
al\t\t\t : " total "M"}'
Node 0, zone Normal : 471.766M
total : 471.766M
/ # cat /proc/meminfo | grep "Slab"
Slab: 18112 kB
如上結果,很明顯,buddy已經將記憶體分配出去了,但是/proc/meminfo中的Slab已經統計不到了。原因就在於kmalloc分配的記憶體大小超過了8KB,不會被統計到Slab,而是以2的指數冪直接從buddy中分配走了。
4.如何檢視所有應用程式消耗的記憶體(不包含核心),單元是MB
注意這個指令碼統計的記憶體偏大,例如共享庫使用的記憶體存在重複統計的情況。ps aux|awk '{sum+=$6} END {print sum/1024}'
原理是統計ps aux的第六列,並求和。該列實際上就是各個程序佔用的實體記憶體
但是需要特別注意的是部分系統可能無法通過ps aux檢視實體記憶體。
注意這個指令碼統計的記憶體更加合理,例如共享庫使用的記憶體不會重複統計,會按比例統計到各個程序中。grep Pss /proc/[1-9]*/smaps | awk '{total+=$2}; END {print total}'