天天看點

一個記憶體增長問題的分析和處理(二)——valgrind工具的用法

valgrind是linux下對C++和C程式進行記憶體洩露檢測的工具,除了記憶體檢測,valgrind還提供了很多其他的功能,這裡主要介紹下valgrind的記憶體檢測的功能。

  首先是檔案的下載下傳,valgrind的官方網址是http://valgrind.org/,最新版本的valgrind是3.9,下載下傳位址如下:http://valgrind.org/downloads/。下載下傳好的檔案是tar.bz2格式的檔案——valgrind-3.9.0.tar.bz2,linux下可以使用tar指令對壓縮包進行解壓,指令如下:

  

tar jxf valgrind-3.9.0.tar.bz2

  解壓後,需要對軟體進行編譯安裝,進入解壓目錄,執行配置指令

./configure

  可以指定路徑安裝,使用 --prefix + 路徑 ,預設的安裝路徑為/usr/local/bin,如果指定了安裝路徑,後續需要把valgrind的安裝路徑配置到PATH環境變量中,接下來是編譯安裝,執行下面的指令

make install

  如果執行指令時發現沒有權限建立目錄,可以使用管理者權限執行,Ubuntu下使用sudo指令即可,安裝完成,執行valgrind --version,如果有版本資訊出現,就安裝成功,否則是安裝失敗。

mengpl@mengpl-

virtual

-machine:/usr/local$ valgrind --version

valgrind-3.9.0

mengpl@mengpl-

virtual

-machine:/usr/local$

  安裝過程中,還遇到另外一個問題

valgrind --leak-check=yes ls -l

==7674== Memcheck, a memory error detector

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

==7674== Using Valgrind-3.8.1 and LibVEX; rerun with -h 

for

copyright info

==7674== Command: ls -l

==7674==

valgrind:  Fatal error at startup: a function redirection

valgrind:  which is mandatory 

for

this

platform-tool combination

  此時需要安裝libc6-dbg庫,Ubuntu下的安裝指令為:

sudo apt-get install libc6-dbg

  正常使用valgrind檢測記憶體的輸出如下:

mengpl@mengpl-

virtual

-machine:/usr/local$ valgrind --leak-check=yes ls

==8260== Memcheck, a memory error detector

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

==8260== Using Valgrind-3.9.0 and LibVEX; rerun with -h 

for

copyright info

==8260== Command: ls

==8260==

bin  etc  games  include  lib  man  sbin  share  src

==8260==

==8260== HEAP SUMMARY:

==8260==     in use at 

exit

: 21,373 bytes in 15 blocks

==8260==   total heap usage: 50 allocs, 35 frees, 58,571 bytes allocated

==8260==

==8260== LEAK SUMMARY:

==8260==    definitely lost: 0 bytes in 0 blocks

==8260==    indirectly lost: 0 bytes in 0 blocks

==8260==      possibly lost: 0 bytes in 0 blocks

==8260==    still reachable: 21,373 bytes in 15 blocks

==8260==         suppressed: 0 bytes in 0 blocks

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

==8260== To see them, rerun with: --leak-check=full --show-leak-kinds=all

==8260==

==8260== For counts of detected and suppressed errors, rerun with: -v

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

  使用valgrind對程式進行分析,主要的使用就是記憶體洩露的分析,也是valgrind預設的工具,valgrind的具體用法,請看man手冊,我這裡隻介紹一種用法,一條指令

valgrind --leak-check=full --show-leak-kinds=all -v

  這個指令 + 需要測試的程式,就可以輸出一套valgrind的統計報告,下面我重點介紹下對于報告的分析,由于我這個程式比較複雜,裡面執行到了很多的内容,我把程式的最終内容進行了歸類,主要分為四部分的内容:

  1)記憶體洩露統計

==6622== LEAK SUMMARY:

==6622==    definitely lost: 1,636 bytes in 9 blocks

==6622==    indirectly lost: 9,421 bytes in 92 blocks

==6622==      possibly lost: 186,418 bytes in 840 blocks

==6622==    still reachable: 728,283 bytes in 1,917 blocks

==6622==         suppressed: 0 bytes in 0 blocks

  2、錯誤統計

ERROR SUMMARY: 3465 errors from 1182 contexts (suppressed: 2 from 2)

  3、記憶體洩露明細

==6622== 152 bytes in 19 blocks are indirectly lost in loss record 1,814 of 1,979

==6622==    at 0x4C2C857: 

malloc

(vg_replace_malloc.c:291)

==6622==    by 0x7614CDB: link_nfa_nodes (regex_internal.c:1000)

==6622==    by 0x761D115: re_compile_internal (regcomp.c:1227)

==6622==    by 0x7620E7E: regcomp (regcomp.c:506)

==6622==    by 0xCE694B5: sal::routecfg::CalRouteHId(

long

long

int

&) (routesalcfg_info.cpp:555)

==6622==    by 0xFC15A46: MRoute::CalcHorIdByMajorDim(

long

long

) (route_common.cpp:141)

==6622==    by 0xFC38736: MRoute::CIRouteImp::query_routeByStr(SOBSession*, 

short

const

&, std::string 

const

&, std::string 

const

&, MRouteDef::SRouteInfo&, CBSErrorMsg&) (route_inf_sdl_i.cpp:411)

==6622==    by 0xFC40E59: MRoute::SearchDbRouteSync(std::string 

const

&, MRouteDef::SRouteInfo&) (route_interface.cpp:10)

==6622==    by 0xFC48D0D: MRoute::search_routing_info(lua_State*) (route_lua_api.cpp:58)

==6622==    by 0xA3899E5: luaD_precall (ldo.cpp:320)

==6622==    by 0xA389C9D: luaD_call (ldo.cpp:377)

==6622==    by 0xA37F1AF: f_call(lua_State*, 

void

*) (lapi.cpp:800)

  4、錯誤明細

==6622== Use of uninitialised value of size 8

==6622==    at 0x9643FD8: ztcedecb (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x96439C1: ztcedencbk (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x9643126: ztcebn (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x9642C46: ztcen (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7DDE0C8: ztceenc (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7E91769: ztcrbm (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7E912F3: ztcrbh (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7E911B5: ztcrbp (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7E910BE: ztcr2seed (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7E91081: ztcrseed3 (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7DDECC7: ztcsh (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

==6622==    by 0x7D35A08: kpusattr (in /opt/oracle/product/10.2.0/client_1/lib/libclntsh.so.11.1)

  首先要對統計資訊進行分析,分為四類資訊,我們來看下官方對于這四類的解釋:

  1、"definitely lost" means your program is leaking memory -- fix those leaks

    這就是記憶體洩露,需要修改

  2、"indirectly lost" means your program is leaking memory in a pointer-based structure. (E.g. if the root node of a binary tree is "definitely lost", all the children will be "indirectly lost".) If you fix the "definitely lost" leaks, the "indirectly lost" leaks should go away.

    這個意思就是說,洩露的記憶體是一個指針,也就是我們平常講的野指針的問題

  3、"still reachable" means your program is probably ok -- it didn’t free some memory it could have. This is quite common and often reasonable. Don’t use --show-reachable=yes if you don’t want to see these reports.

    你的程式可能是好的,意思是,在程式沒有結束之前,這部分記憶體一直都沒有釋放

  4、"suppressed" means that a leak error has been suppressed. There are some suppressions in the default suppression files. You can ignore suppressed errors.

    這個可以直接忽略

  記憶體洩露的明細中,會表示出來每一個可能存在記憶體洩露的地方,可以逐個進行分析,當遇到情況比較多的情況,可以對這些進行分類,在具體分析代碼。

  錯誤明細中,也會存在幾種情況,我例子中提到的Use of uninitialised value of size 8 記憶體沒有初始化等。具體的valgrind的用法,推薦一篇檔案

https://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

  這裡面介紹的非常詳細和周到。

  關于記憶體增長的問題,還沒有定位到具體的位置,後續如果定位到,會把結果補充上來。

繼續閱讀