星期四, 5月 07, 2020

How to detect Linux memory leak?

https://blog.xuite.net/antony0604/blog/254546994


最近所參與開發的linux系統發生了,死機的情形. http 還可連入, 但整個動作非常的慢.
在console mode下, 打 top 命令也非常慢才出現, 而看不到任何一支程式吃掉CPU,
但system CPU 佔全部的 80% 以上. 之後再仔細看到memory free剩非常的少(跟剛開機的時侯相比)
故而懷疑是 memory leak 導致的, 於是寫了一支程式去吃記憶體, 複製發生異常時,情形是否一致.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
 printf("this program will eat memory 1M every 10 seconds\n");
 int i = 0;
 while (1){
  i++;
  sleep(10);
  if (i<= 50) {
   char* leak_mem;
   leak_mem = malloc (1024*1024);
   int iValue = i % 256;
   memset(leak_mem,iValue,1024*1024);
   int j=0;
   for ( j=0; j< 1024*1024; j++)
   {
    leak_mem[j] = (iValue+j) % 256;
   }
   printf("%d. eat 1M memory now ... %d %d ~ %d %d \n", i,leak_mem[0],leak_mem[1],leak_mem[1024*1024-2],leak_mem[1024*1024-1]);
  }
 }
 printf("this program exit now \n");
}
由於Linux如果將吃掉記憶的程式砍掉的話, 其記憶體還是會被釋放回來, 故而當吃掉一定程度的記憶體之後, 即開始休息(不要離開程式, 否則會釋放回去). 另外allocate的記憶體須要memset,才會真的使用到.
 可以用來看系統CPU分配的情形, 可以經由top 中的Load average, 其欄位分別記錄著過去時間有多少程式須共用一個CPU, 分別是1/5/15 分鐘. 也可經由下列指令得知 cat /proc/loadavg
另外top也可以有不同的排序方式 N/M/P/T (show CPU usage, sort by pid/mem/cpu/time) . 而top 也能看到記憶使用的仔細情形 ( S: show memory), 可以觀察到VSZ RSS 的使用情形.

想要得知某一程式有多少執行緒正在執行, 命令如下:
ps -T | grep process-name
如果要得知wis-stream 有多少個執行緒在執行, 則範例如下(除了主程式外還有四個子執行緒):
#
# ps -T | grep wis-stream
 1376 root      56:19 /bin/wis-streamer
 1377 root       0:01 /bin/wis-streamer
 1378 root       0:00 /bin/wis-streamer
 1379 root       0:00 /bin/wis-streamer
 1380 root       0:00 /bin/wis-streamer
15792 root       0:00 grep wis-stream
#
而要查看某一執行緒(pid) , 有執行那些 system call 的指令會特別佔用記憶體, 則用下列命令去查詢:
strace -c -p PidOfThread
strace此會attech 到此pid ,直到你中斷它的執行(Ctrl-C), 如要看上述wis-streamer的情形如下:
# strace -c -p 1376
Process 1376 attached - interrupt to quit
^CProcess 1376 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.10    0.220000         280       785           select
  2.90    0.006581           3      2501           gettimeofday
------ ----------- ----------- --------- --------- ----------------
100.00    0.226581                  3286           total
#
可以得知大部分的CPU 都在執行select 這個system call 上面.
那些命令屬於 system call , 可以查詢下列網址  Linux System Call Table

要看記憶體使用的情形, 可以用下列命令:
free -m
cat /proc/meminfo
top (執行之後再按大寫 S)
pidstat -r 10 -p ALL
其中以 pidstat 較好用, 它可以看到所有程式佔用記憶體的情形
# pidstat -r 10 -p ALL
Linux 2.6.38.8 (VN-H228)        11/18/14        _armv6l_        (1 CPU)
11:37:17          PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
11:37:28            1      0.00      0.00    3272    700   0.66  linuxrc
11:37:28          823      0.00      0.00    2532    968   0.91  check_daemon
11:37:28          826      0.00      0.00    3784   1164   1.09  syslogd
11:37:28          828      0.00      0.00    3276    660   0.62  logger
11:37:28          830      0.00      0.00   12224   1476   1.39  topbus
11:37:28          837      0.10      0.00   60608   2988   2.81  topservice
11:37:28          842      0.00      0.00    3272    328   0.31  telnetd
11:37:28          843      0.00      0.00    3276    728   0.68  sh
11:37:28          874      0.00      0.00       0      0   0.00  loop0
11:37:28          875      0.00      0.00       0      0   0.00  ext4-dio-unwrit
11:37:28          943      0.00      0.00       0      0   0.00  dsplogd
11:37:28          944      0.00      0.00       0      0   0.00  vsyncd
11:37:28          958      0.00      0.00       0      0   0.00  hdmid
11:37:28          967      0.00      0.00  279680   1324   1.24  capture_server
11:37:28          979      0.00      0.00  164904   1056   0.99  encode_server
11:37:28          982      0.00      0.00   69304   1704   1.60  tv_3a_service
11:37:28          989      0.00      0.00   30872   3992   3.75  jackd
11:37:28         1028      0.00      0.00   18716    800   0.75  check_auth
11:37:28         1033      0.00      0.00    2300    672   0.63  detection
11:37:28         1036      0.00      0.00    2676   1128   1.06  fget
11:37:28         1039      0.00      0.00    2292    556   0.52  fset
11:37:28         1041      0.00      0.00   18596    848   0.80  ieee8021x
11:37:28         1104      0.00      0.00    2436    780   0.73  yaweb
11:37:28         1120      0.00      0.00   60444    788   0.74  ftp_service
11:37:28         1122      0.00      0.00   60460    712   0.67  email_service
11:37:28         1124      0.00      0.00   18388    540   0.51  sd_service
11:37:28         1126      0.00      0.00   43256    968   0.91  event_service
11:37:28         1155      0.00      0.00   30128   1136   1.07  subscriberman
11:37:28         1157      0.10      0.00   26668    760   0.71  tv_wsdiscovery
11:37:28         1159      0.00      0.00    1868    412   0.39  dbgsvr
11:37:28         1161      0.00      0.00   18392    620   0.58  FocusAssist
11:37:28         1163      0.00      0.00   18396    620   0.58  alarmserver
11:37:28         1169      0.00      0.00   18428    564   0.53  scan_port
11:37:28         1171      0.00      0.00   48360   2324   2.18  audio_server
11:37:28         1173      0.00      0.00   23780   2180   2.05  jvc_audio_clien
11:37:28         1175      0.00      0.00   40176   2212   2.08  audio_read
11:37:28         1204      0.00      0.00   21800    492   0.46  subscriberman
11:37:28         1213      0.00      0.00   18500    664   0.62  jvc_search
11:37:28         1234      0.00      0.00   18500    664   0.62  jvc_search
11:37:28         1246      0.29      0.00   12072   4008   3.77  upnpd
11:37:28         1272      0.00      0.00   43020    796   0.75  rtsp_client
11:37:28         1281      0.00      0.00   10204    624   0.59  ipfinder
11:37:28         1316      0.00      0.00   24604   4176   3.92  snmpd
11:37:28         1376      0.00      0.00   93700   1828   1.72  wis-streamer
11:37:28         1619      0.00      0.00    5736   2032   1.91  lighttpd
11:37:28         1660      0.00      0.00   79444   1972   1.85  rtsp_over_http
11:37:28         1774      0.00      0.00   82516   1808   1.70  rtsp_over_http
11:37:28         6321      0.00      0.00       0      0   0.00  kworker/0:0
11:37:28         7513      0.00      0.00       0      0   0.00  kworker/0:4
11:37:28        15898      0.00      0.00       0      0   0.00  flush-ubifs_0_0
11:37:28        15899      0.00      0.00       0      0   0.00  flush-7:0
如果有那支程式的RSS欄位一直在增長, 則表示此程序有可能是造成memory leak的元凶.此處不能光看VSZ欄位, 因為VSZ 有可能只是allocate memory, 但並沒有真的使用它.
而RSS欄位的增長有時是因為使用到ShareMemory的關後, 所以要配合看free memory是否有減少, 才能正確判斷是否一直吃記憶體.
PS 2019/6/18: 如果採用ram拿來當linux aufs , 則檔案一直寫入增大的話, 會導致memory cache一直增大; 最後可用的記憶體會被吃光而當機. 所以不能有任何程式一直讓檔案變大.
另外, 試了 valgrind , 可以用來偵測 memory leak的問題. 但由於ld-uClibc-0.9.33.2.so 是stripped, 所以cross-compile之後無法有效偵測memory.
d-uClibc-0.9.33.2.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, stripped
2 - 不要使用完全剝離的Linux發行版/lib/ld.so。(比如上面的getoff-arm-linux 就連結了 /lib/ld-uClibc.so.0, 那就要求我們的開發板根目錄下的/lib/ld-uClibc.so.0 必須是 not stripped)
refernce of valgrind as follow:

沒有留言: