歡迎您光臨本站 註冊首頁

防止內存泄露 Linux下用Valgrind做檢查

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0

  用C/C 開發其中最令人頭疼的一個問題就是內存管理,有時候為了查找一個內存泄漏或者一個內存訪問越界,需要要花上好幾天時間,如果有一款工具能夠幫助我們做這件事情就好了,valgrind正好就是這樣的一款工具.

  Valgrind是一款基於模擬linux下的程序調試器和剖析器的軟體套件,可以運行於x86, amd64和ppc32架構上.valgrind包含一個核心,它提供一個虛擬的CPU運行程序,還有一系列的工具,它們完成調試,剖析和一些類似的任務.valgrind是高度模塊化的,所以開發人員或者用戶可以給它添加新的工具而不會損壞己有的結構.

  valgrind的官方網址是:http://valgrind.org

  你可以在它的網站上下載到最新的valgrind,它是開放源碼和免費的.

  一、介紹

  valgrind包含幾個標準的工具,它們是:

  1、memcheck

  memcheck探測程序中內存管理存在的問題.它檢查所有對內存的讀/寫操作,並截取所有的malloc/new/free/delete調用.因此memcheck工具能夠探測到以下問題:

  1)使用未初始化的內存

  2)讀/寫已經被釋放的內存

  3)讀/寫內存越界

  4)讀/寫不恰當的內存棧空間

  5)內存泄漏

  6)使用malloc/new/new[]和free/delete/delete[]不匹配.

  2、cachegrind

  cachegrind是一個cache剖析器.它模擬執行CPU中的L1, D1和L2 cache,因此它能很精確的指出代碼中的cache未命中.如果你需要,它可以列印出cache未命中的次數,內存引用和發生cache未命中的每一行代碼,每一個函數,每一個模塊和整個程序的摘要.如果你要求更細緻的信息,它可以列印出每一行機器碼的未命中次數.在x86和amd64上,cachegrind通過CPUID自動探測機器的cache配置,所以在多數情況下它不再需要更多的配置信息了.

  3、helgrind

  helgrind查找多線程程序中的競爭數據.helgrind查找內存地址,那些被多於一條線程訪問的內存地址,但是沒有使用一致的鎖就會被查出.這表示這些地址在多線程間訪問的時候沒有進行同步,很可能會引起很難查找的時序問題.

  二、valgrind對你的程序都做了些什麼

  valgrind被設計成非侵入式的,它直接工作於可執行文件上,因此在檢查前不需要重新編譯、連接和修改你的程序.要檢查一個程序很簡單,只需要執行下面的命令就可以了

  valgrind --tool=tool_name program_name

  比如我們要對ls -l命令做內存檢查,只需要執行下面的命令就可以了

  valgrind --tool=memcheck ls -l

  不管是使用哪個工具,valgrind在開始之前總會先取得對你的程序的控制權,從可執行關聯庫里讀取調試信息.然後在valgrind核心提供的虛擬CPU上運行程序,valgrind會根據選擇的工具來處理代碼,該工具會向代碼中加入檢測代碼,並把這些代碼作為最終代碼返回給valgrind核心,valgrind核心運行這些代碼.

  如果要檢查內存泄漏,只需要增加--leak-check=yes就可以了,命令如下

  valgrind --tool=memcheck --leak-check=yes ls -l

  不同工具間加入的代碼變化非常的大.在每個作用域的末尾,memcheck加入代碼檢查每一片內存的訪問和進行值計算,代碼大小至少增加12倍,運行速度要比平時慢25到50倍.

  valgrind模擬程序中的每一條指令執行,因此,檢查工具和剖析工具不僅僅是對你的應用程序,還有對共享庫,GNU C庫,X的客戶端庫都起作用.

  三、現在開始

  ,在編譯程序的時候打開調試模式(gcc編譯器的-g選項).如果沒有調試信息,即使最好的valgrind工具也將中能夠猜測特定的代碼是屬於哪一個函數.打開調試選項進行編譯后再用valgrind檢查,valgrind將會給你的個詳細的報告,比如哪一行代碼出現了內存泄漏.

  當檢查的是C 程序的時候,還應該考慮另一個選項 -fno-inline.它是的函數調用鏈很清晰,這樣可以減少你在瀏覽大型C 程序時的混亂.比如在使用這個選項的時候,用memcheck檢查openoffice就很容易.當然,你可能不會做這項工作,但是使用這一選項是的valgrind生成更精確的錯誤報告和減少混亂.

  一些編譯優化選項(比如-O2或者更高的優化選項),可能會是的memcheck提交錯誤的未初始化報告,因此,為了是的valgrind的報告更精確,在編譯的時候最好不要使用優化選項.

  如果程序是通過腳本啟動的,可以修改腳本里啟動程序的代碼,或者使用--trace-children=yes選項來運行腳本.

  下面是用memcheck檢查ls -l命令的輸出報告,在終端下執行下面的命令

  valgrind --tool=memcheck ls -l

  程序會列印出ls -l命令的結果,是valgrind的檢查報告如下:

  ==4187==

  ==4187== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 2)

  ==4187== malloc/free: in use at exit: 15,154 bytes in 105 blocks.

  ==4187== malloc/free: 310 allocs, 205 frees, 60,093 bytes allocated.

  ==4187== For counts of detected errors, rerun with: -v

  ==4187== searching for pointers to 105 not-freed blocks.

  ==4187== checked 145,292 bytes.

  ==4187==

  ==4187== LEAK SUMMARY:

  ==4187== definitely lost: 0 bytes in 0 blocks.

  ==4187== possibly lost: 0 bytes in 0 blocks.

  ==4187== still reachable: 15,154 bytes in 105 blocks.

  ==4187== suppressed: 0 bytes in 0 blocks.

  ==4187== Reachable blocks (those to which a pointer was found) are not shown.

  ==4187== To see them, rerun with: --show-reachable=yes

  這裡的「4187」指的是執行ls -l的進程ID,這有利於區別不同進程的報告.memcheck會給出報告,分配置和釋放了多少內存,有多少內存泄漏了,還有多少內存的訪問是可達的,檢查了多少位元組的內存.

  下面舉兩個用valgrind做內存檢查的例子

  例子一 (test.c):

  #include <string.h>

  int main(int argc, char *argv[])

  {

  char *ptr;

  ptr = (char*) malloc(10);

  strcpy(ptr, "01234567890");

  return 0;

  }

  編譯程序

  gcc -g -o test test.c

  用valgrind執行命令

  valgrind --tool=memcheck --leak-check=yes ./test

  報告如下

  ==4270== Memcheck, a memory error detector.

  ==4270== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.

  ==4270== Using LibVEX rev 1606, a library for dynamic binary translation.

  ==4270== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.

  ==4270== Using valgrind-3.2.0, a dynamic binary instrumentation framework.

  ==4270== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.

  ==4270== For more details, rerun with: -v

  ==4270==

  ==4270== Invalid write of size 1

  ==4270== at 0x4006190: strcpy (mc_replace_strmem.c:271)

  ==4270== by 0x80483DB: main (test.c:8)

  ==4270== Address 0x4023032 is 0 bytes after a block of size 10 alloc'd

  ==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

  ==4270== by 0x80483C5: main (test.c:7)

  ==4270==

  ==4270== Invalid write of size 1

  ==4270== at 0x400619C: strcpy (mc_replace_strmem.c:271)

  ==4270== by 0x80483DB: main (test.c:8)

  ==4270== Address 0x4023033 is 1 bytes after a block of size 10 alloc'd

  ==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

  ==4270== by 0x80483C5: main (test.c:7)

  ==4270==

  ==4270== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 12 from 1)

  ==4270== malloc/free: in use at exit: 10 bytes in 1 blocks.

  ==4270== malloc/free: 1 allocs, 0 frees, 10 bytes allocated.

  ==4270== For counts of detected errors, rerun with: -v

  ==4270== searching for pointers to 1 not-freed blocks.

  ==4270== checked 51,496 bytes.

  ==4270==

  ==4270==

  ==4270== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1

  ==4270== at 0x40044F6: malloc (vg_replace_malloc.c:149)

  ==4270== by 0x80483C5: main (test.c:7)

  ==4270==

  ==4270== LEAK SUMMARY:

  ==4270== definitely lost: 10 bytes in 1 blocks.

  ==4270== possibly lost: 0 bytes in 0 blocks.

  ==4270== still reachable: 0 bytes in 0 blocks.

  ==4270== suppressed: 0 bytes in 0 blocks.

  ==4270== Reachable blocks (those to which a pointer was found) are not shown.

  ==4270== To see them, rerun with: --show-reachable=yes

  從這份報告可以看出,進程號是4270,test.c的第8行寫內存越界了,引起寫內存越界的是strcpy函數,

  第7行泄漏了10個位元組的內存,引起內存泄漏的是malloc函數.

  例子二(test2.c)

  #include <stdio.h>

  int foo(int x)

  {

  if (x < 0) {

  printf("%d ", x);

  }

  return 0;

  }

  int main(int argc, char *argv[])

  {

  int x;

  foo(x);

  return 0;

  }

  編譯程序

  gcc -g -o test2 test2.c

  用valgrind做內存檢查

  valgrind --tool=memcheck ./test2

  輸出報告如下

  ==4285== Memcheck, a memory error detector.

  ==4285== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.

  ==4285== Using LibVEX rev 1606, a library for dynamic binary translation.

  ==4285== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.

  ==4285== Using valgrind-3.2.0, a dynamic binary instrumentation framework.

  ==4285== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.

  ==4285== For more details, rerun with: -v

  ==4285==

  ==4285== Conditional jump or move depends on uninitialised value(s)

  ==4285== at 0x8048372: foo (test2.c:5)

  ==4285== by 0x80483B4: main (test2.c:16)

  ==4285==p p

  ==4285== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)

  ==4285== malloc/free: in use at exit: 0 bytes in 0 blocks.

  ==4285== malloc/free: 0 allocs, 0 frees, 0 bytes allocated.

  ==4285== For counts of detected errors, rerun with: -v

  ==4285== All heap blocks were freed -- no leaks are possible.

  從這份報告可以看出進程PID是4285,test2.c文件的第16行調用了foo函數,在test2.c文件的第5行foo函數使用了一個未初始化的變數.

  valgrind還有很多使用選項,具體可以查看valgrind的man手冊頁和valgrind官方網站的在線文檔.

  文章來自[SVN中文技術網]轉發請保留本站地址:linux/accidence/20091022/11249_2.html">http://www.svn8.com/linux/accidence/20091022/11249_2.html

  以下來自另一篇博文:http://cnlinzhimao.blog.163.com/blog/static/23527872200881593621867/

  Valgrind是一個GPL的軟體,用於Linux(For x86, amd64 and ppc32)程序的內存調試和代碼剖析.你可以在它的環境中運行你的程序來監視內存的使用情況,比如C 語言中的malloc和free或者 C 中的new和 delete.使用Valgrind的工具包,你可以自動的檢測許多內存管理和線程的bug,避免花費太多的時間在bug尋找上,是的你的程序更加穩固.

  Valgrind的主要功能

  Valgrind工具包包含多個工具,如Memcheck,Cachegrind,Helgrind, Callgrind,Massif.下面分別介紹個工具的作用:

  Memcheck 工具主要檢查下面的程序錯誤:

  使用未初始化的內存 (Use of uninitialised memory)

  使用已經釋放了的內存 (Reading/writing memory after it has been free』d)

  使用超過 malloc分配的內存空間(Reading/writing off the end of malloc』d blocks)

  對堆棧的非法訪問 (Reading/writing inappropriate areas on the stack)

  申請的空間是否有釋放 (Memory leaks – where pointers to malloc』d blocks are lost forever)

  malloc/free/new/delete申請和釋放內存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])

  src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)

  Callgrind

  Callgrind收集程序運行時的一些數據,函數調用關係等信息,還可以有選擇地進行cache 模擬.在運行結束時,它會把分析數據寫入一個文件.callgrind_annotate可以把這個文件的內容轉化成可讀的形式.

  Cachegrind

  它模擬 CPU中的一級緩存I1,D1和L2二級緩存,能夠精確地指出程序中 cache的丟失和命中.如果需要,它還能夠為我們提供cache丟失次數,內存引用次數,以及每行代碼,每個函數,每個模塊,整個程序產生的指令數.這對優化程序有很大的幫助.

  Helgrind

  它主要用來檢查多線程程序中出現的競爭問題.Helgrind 尋找內存中被多個線程訪問,而又沒有一貫加鎖的區域,這些區域往往是線程之間失去同步的地方,會導致難以發掘的錯誤.Helgrind實現了名為」 Eraser」 的競爭檢測演算法,並做了進一步改進,減少了報告錯誤的次數.

  Massif

  堆棧分析器,它能測量程序在堆棧中使用了多少內存,告訴我們堆塊,堆管理塊和棧的大小.Massif能幫助我們減少內存的使用,在帶有虛擬內存的現代系統中,它還能夠加速我們程序的運行,減少程序停留在交換區中的幾率.

  Valgrind 安裝

  1、 到www.valgrind.org下載最新版valgrind-3.2.3.tar.bz2

  2、 解壓安裝包:tar –jxvf valgrind-3.2.3.tar.bz2

  3、 解壓後生成目錄valgrind-3.2.3

  4、 cd valgrind-3.2.3

  5、 ./configure6、 Make;make install

  1.檢查內存錯誤:

  例如我們原來有一個程序sec_infod,這是一個用gcc –g參數編譯的程序,運行它需要:

  #./a.out

  如果我們想用valgrind的內存檢測工具,我們就要用如下方法調用:

  #valgrind --leak-check=full --show-reachable=yes --trace-children= yes ./a.out (2>logfile加上會好些,程序在執行期間stderr會有一些輸出.提示比較多)

  其中--leak-check=full 指的是完全檢查內存泄漏,--show-reachable=yes是顯示內存泄漏的地點,--trace-children=yes是跟入子進程.

  如果您的程序是會正常退出的程序,那麼當程序退出的時候valgrind自然會輸出內存泄漏的信息.如果您的程序是個守護進程,那麼也不要緊,我們只要在別的終端下殺死memcheck進程(valgrind默認使用memcheck工具,就是默認參數—tools=memcheck):

  #killall memcheck

  這樣我們的程序(./a.out)就被kill了

  2,檢查代碼覆蓋和性能瓶頸:

  我們調用valgrind的工具執行程序:

  #valgrind --tool=callgrind ./sec_infod

  會在當前路徑下生成callgrind.out.pid(當前生產的是callgrind.out.19689),如果我們想結束程序,可以:

  #killall callgrind

  然後我們看一下結果:

  #callgrind_annotate --auto=yes callgrind.out.19689 >log

  #vim log

  3.Valgrind使用參數

  --log-fd=N 默認情況下,輸出信息是到標準錯誤stderr,也可以通過—log-fd=8,輸出到描述符為8的文件

  --log-file=filename將輸出的信息寫入到filename.PID的文件里,PID是運行程序的進行ID.可以通過--log-file exactly=filename指定就輸出到filename文件.

  --log-file-qualifier=<VAR>,取得環境變數的值來做為輸出信息的文件名.如—log-file-qualifier=$FILENAME.

  --log-socket=IP:PORT 也可以把輸出信息發送到網路中指定的IP:PORT去

  --error-limit=no 對錯誤報告的個數據進行限制,默認情況不做限制

  --tool=<toolname> [default: memcheck]

  --tool=memcheck:要求用memcheck這個工具對程序進行分析

  --leak-ckeck=yes 要求對leak給出詳細信息

  --trace-children=<yes|no> [default: no]跟蹤到子進程里去,默認請況不跟蹤

  --xml=<yes|no> [default: no]將信息以xml格式輸出,只有memcheck可用

  --gen-suppressions=<yes|no|all> [default: no]如果為yes,valgrind會在每發現一個錯誤便停下讓用戶做選擇是繼續還是退出

  更多選項請參看: http://www.valgrind.org/docs/manual/manual-core.html可以把一些默認選項編輯在 ~/.valgrindrc文件里.

  這裡使用valgrind的memcheck和callgrind兩個工具的用法,其實valgrind還有幾個工具:「cachegrind」,用於檢查緩存使用的;「helgrind」用於檢測多線程競爭資源的,等等.


[火星人 ] 防止內存泄露 Linux下用Valgrind做檢查已經有704次圍觀

http://coctec.com/docs/linux/show-post-50704.html