分享一個輔助分析內存泄漏的腳本

  最近給系統作了一點優化,前幾天去查看系統監控,想看看上線先後cpu使用率曲線變化狀況。查看的時候意外發現上線先後內存佔用相差很多,20%以上。緩存

原本我沒怎麼在乎這個問題,由於咱們系統會在運行過程當中緩存部分數據內容。但客戶以爲有異常,堅持要查。因而把一個月的內存使用狀況調出來看,這一看就發現問題了:優化

  系統內存佔用確實是在緩慢增長,一兩天的內存使用率曲線看不出什麼,但一個月的能夠明顯看出來,是一條斜率很小的直線。spa

  發現了有內存泄漏,可是想具體分析是哪一個進程泄漏的還真很差辦。由於咱們系統有上千個進程在跑,而監控系統又只記錄了整體內存佔用狀況,沒記錄單個進程內存佔用。設計

  沒有槍,沒有炮,只能本身來造 :) 。 我設計了一個簡單的分析方法:code

  1 首先,我寫一個腳本,天天按期記錄系統全部進程使用狀況,保存到文件,以時間戳命名。(用ps實現)blog

  2 腳本跑幾天後,我再使用另外一個腳本,把文件合併起來分析,把每一個進程在不一樣時間點的內存使用狀況合併成一行,逐個進程輸出排序

  3 比較每一個進程第一次出現與最後一次出現時佔用內存之差,按從小到大排序,便可得出可能存在內存泄漏的程序。進程

  效果以下:能夠看出這個進程內存佔用一直在增長,從第一次統計到最後一次統計之間內存使用增長了1460k內存

  知道問題後就好辦了,使用valgrind+gdb很快就找出致使內存泄漏的代碼,糾正便可。class

 

  下面是分析過程當中用到的腳本,但願對你們有幫助

 1 # 20190228 hch 輔助分析程序內存泄漏狀況的腳本
 2 # 設計思路:首先用ps按期採集全部程序佔用內存狀況,生成多個文件。而後使用awk分析ps輸出的文件,把相同進程佔用的內存合併成一行輸出
 3 # 計算進程第一次和最後一次出現的時間點佔用內存之差,逆序輸出便可得到疑似內存泄漏的程序
 4 
 5 # 首先使用如下腳本採集程序每一分鐘內存佔用信息,採集若干分鐘
 6 # while [ 1 ]; do ps -eo 'pid,comm,rsz,vsz,user,comm,args,pcpu,pmem' --sort rsz > ps_info_$(date "+%Y%m%d%H%M%S").txt ; sleep 60; done
 7 
 8 # 使用awk腳本分析內存佔用信息 把進程每個時間點的內存佔用狀況合併成一行方便對比
 9 # 而且統計進程第一次出現和最後一次出現佔用內存差,輸出
10 awk '{
11     # 每次處理一個新文件時須要特殊處理一下 
12     if (FNR == 1) {
13         # 登記文件名稱
14         v_all_file_name = v_all_file_name "," FILENAME;
15         v_prefix_str = v_prefix_str ",";
16         ++v_file_cnt;
17         
18         # 把上次文件沒有出現的pid補上
19         if (NR != 1) { # FNR == 1 && NR == 1 表明第一個文件
20             for (v_pid_name in v_mp_pid_cnt) {
21                 if (v_mp_pid_cnt[v_pid_name] != v_file_cnt - 1) {
22                     v_mp_pid_rsz[v_pid_name] = v_mp_pid_rsz[v_pid_name] ","
23                     v_mp_pid_vsz[v_pid_name] = v_mp_pid_vsz[v_pid_name] ","
24                     v_mp_pid_cnt[v_pid_name] = v_file_cnt - 1;
25                 }
26             }
27         }
28     }
29     
30     v_pid_name = $2 "-" $1 "-" $5; #程序名-進程號-用戶名
31     # 非第一個文件,第一次出現,須要補齊","
32     if (v_file_cnt != 1 && v_mp_pid_cnt[v_pid_name] == 0) {
33         v_mp_pid_rsz[v_pid_name] = v_mp_pid_vsz[v_pid_name] = substr(v_prefix_str, 1, v_file_cnt - 1);
34         v_mp_pid_cnt[v_pid_name] = v_file_cnt - 1;
35     }
36     
37     # rsz是物理內存 單位k
38     v_mp_pid_rsz[v_pid_name] = v_mp_pid_rsz[v_pid_name] "," $3
39     # 記錄最後值和初始值 方便後面分析(有須要能夠改爲最大和最小值)
40     #if ($3 > v_mp_pid_rsz_max[v_pid_name]) v_mp_pid_rsz_max[v_pid_name] = $3;
41     v_mp_pid_rsz_max[v_pid_name] = $3;
42     if (v_mp_pid_rsz_min[v_pid_name] == 0 ) # || $3 < v_mp_pid_rsz_min[v_pid_name]
43         v_mp_pid_rsz_min[v_pid_name] = $3;
44     
45     # vsz是虛存 單位k
46     v_mp_pid_vsz[v_pid_name] = v_mp_pid_vsz[v_pid_name] "," $4
47     v_mp_pid_vsz_max[v_pid_name] = $4;
48     if (v_mp_pid_vsz_min[v_pid_name] == 0 ) # || $4 < v_mp_pid_rsz_min[v_pid_name]
49         v_mp_pid_vsz_min[v_pid_name] = $4;
50         
51     # 在本文件出現過就標記一下,後面文件處理完後才知道哪些進程沒出現
52     v_mp_pid_cnt[v_pid_name] = v_file_cnt;
53 }
54 END {
55     print v_all_file_name
56     for (v_pid_name in v_mp_pid_rsz) {
57         print "rsz:"v_pid_name, v_mp_pid_rsz_max[v_pid_name] - v_mp_pid_rsz_min[v_pid_name], v_mp_pid_rsz[v_pid_name]
58         print "vsz:"v_pid_name, v_mp_pid_vsz_max[v_pid_name] - v_mp_pid_vsz_min[v_pid_name], v_mp_pid_vsz[v_pid_name];
59     }
60 }' $(ls -rt ps_inf*txt) > ps_trace.txt #按時間逆序分析
61 
62 # 將分析結果排序輸出
63 # sh ps_trace.sh; sork -k2n ps_trace.txt | tail -100
相關文章
相關標籤/搜索