記憶體排查 valgrind

來源:互聯網
上載者:User

標籤:

記憶體問題排查工具 --- valgrind

  • 1. 概述
  • 2. Valgrind
  • 3. 記憶體流失監測
    • 3.1. 範例程式碼
    • 3.2. 編譯它
    • 3.3. 用Valgrind監測進程的記憶體流失
  • 4. 懸掛指標
    • 4.1. 範例程式碼
    • 4.2. Valgrind運行結果
  • 5. 多次釋放同一個指標
    • 5.1. 範例程式碼
    • 5.2. Valgrind 監測
  • 6. Valgrind的優缺點
    • 6.1. Advantages
    • 6.2. Disadvantages
  • 7. Valgrind的其他工具
    • 7.1. Cachegrind
    • 7.2. Callgrind
    • 7.3. Helgrind
    • 7.4. DRD
    • 7.5. Massif
    • 7.6. DHAT
  • 8. 參考
1 概述

在用C/C++編程的時候,經常會出現下面三種記憶體問題:

  • 記憶體流失
  • 懸掛指標
  • 多次釋放同一塊記憶體

本系列文章簡要介紹排查這三個問題的工具和方法,先看看Valgrind

2 Valgrind

Valgrind是一款可以監測記憶體使用量情況、監測記憶體流失的工具。對於一些規模不是很大的應用程式,Valgrind是一把利器。

3 記憶體流失監測3.1 範例程式碼
 1: int main() 2: { 3:     char *p = malloc(sizeof(char) * 10); 4:     if (p == NULL) { 5:         return 0; 6: } 7:  8: *p++ = ‘a‘; 9: *p++ = ‘b‘;10: 11: printf("%s\n", *p);12: 13: return 0;14: }
3.2 編譯它
1: gcc -g -o core1 core1.c
3.3 用Valgrind監測進程的記憶體流失
1: valgrind --leak-check=yes --show-reachable=yes ./core

Valgrind的輸出為為:

 1: ==25500== Memcheck, a memory error detector 2: ==25500== Copyright (C) 2002-2009, and GNU GPL‘d, by Julian Seward et al. 3: ==25500== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 4: ==25500== Command: ./core1 5: ==25500== 6: ==25500== Conditional jump or move depends on uninitialised value(s) 7: ==25500== at 0x36A104546A: vfprintf (in /lib64/libc-2.12.so) 8: ==25500== by 0x36A104EAC9: printf (in /lib64/libc-2.12.so) 9: ==25500== by 0x40055D: main (core1.c:13)10: ==25500==11: (null)12: ==25500==13: ==25500== HEAP SUMMARY:14: ==25500== in use at exit: 10 bytes in 1 blocks15: ==25500== total heap usage: 1 allocs, 0 frees, 10 bytes allocated16: ==25500==17: ==25500== 10 bytes in 1 blocks are definitely lost in loss record 1 of 118: ==25500== at 0x4A0515D: malloc (vg_replace_malloc.c:195)19: ==25500== by 0x400515: main (core1.c:5)20: ==25500==21: ==25500== LEAK SUMMARY:22: ==25500== definitely lost: 10 bytes in 1 blocks23: ==25500== indirectly lost: 0 bytes in 0 blocks24: ==25500== possibly lost: 0 bytes in 0 blocks25: ==25500== still reachable: 0 bytes in 0 blocks26: ==25500== suppressed: 0 bytes in 0 blocks27: ==25500==28: ==25500== For counts of detected and suppressed errors, rerun with: -v29: ==25500== Use --track-origins=yes to see where uninitialised values come from30: ==25500== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)

可以看到,Valgrind提示在第五行分配的記憶體未被釋放

4 懸掛指標4.1 範例程式碼
 1: struct elem { 2:     int     a; 3:     double  b; 4: }; 5:  6: int main() 7: { 8: struct elem *e = malloc(sizeof(struct elem)); 9: if (e == NULL) {10: return 0;11: }12: 13: e->a = 10;14: e->b = 10.10;15: 16: double *xx = &e->b;17: 18: printf("%f\n", *xx);19: 20: free(e);21: 22: printf("%f\n", *xx);23: 24: return 0;25: }
4.2 Valgrind運行結果

同樣用-g編譯後valgrind啟動並執行結果:

 1: [[email protected]]$ valgrind --leak-check=yes --show-reachable=yes ./core2 2: ==26148== Memcheck, a memory error detector 3: ==26148== Copyright (C) 2002-2009, and GNU GPL‘d, by Julian Seward et al. 4: ==26148== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 5: ==26148== Command: ./core2 6: ==26148== 7: 10.100000 8: ==26148== Invalid read of size 8 9: ==26148== at 0x4005CA: main (core2.c:26)10: ==26148== Address 0x502a048 is 8 bytes inside a block of size 16 free‘d11: ==26148== at 0x4A04D72: free (vg_replace_malloc.c:325)12: ==26148== by 0x4005C5: main (core2.c:24)13: ==26148==14: 10.10000015: ==26148==16: ==26148== HEAP SUMMARY:17: ==26148== in use at exit: 0 bytes in 0 blocks18: ==26148== total heap usage: 1 allocs, 1 frees, 16 bytes allocated19: ==26148==20: ==26148== All heap blocks were freed -- no leaks are possible21: ==26148==22: ==26148== For counts of detected and suppressed errors, rerun with: -v23: ==26148== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)

可以看到在free(e)後,指標xx成為了懸掛指標,此後對xx的讀,如果xx指向的記憶體還未被glibc回收,進程不會core掉。valgrind提示在26行做了對xx的 Invalid read.

5 多次釋放同一個指標 5.1 範例程式碼
 1: int main() 2: { 3:     char *p = malloc(sizeof(char) * 10); 4:     if (p == NULL) { 5:         return 0; 6: } 7:  8: char *q = p; 9: 10: *p++ = ‘a‘;11: *p++ = ‘b‘;12: 13: printf("%s\n", *p);14: 15: free(p);16: free(q);17: return 0;18: }
5.2 Valgrind 監測
 1: [[email protected]]$ valgrind --leak-check=yes --show-reachable=yes ./core1 2: ==26874== Memcheck, a memory error detector 3: ==26874== Copyright (C) 2002-2009, and GNU GPL‘d, by Julian Seward et al. 4: ==26874== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info 5: ==26874== Command: ./core1 6: ==26874== 7: ==26874== Conditional jump or move depends on uninitialised value(s) 8: ==26874== at 0x36A104546A: vfprintf (in /lib64/libc-2.12.so) 9: ==26874== by 0x36A104EAC9: printf (in /lib64/libc-2.12.so)10: ==26874== by 0x4005B5: main (core1.c:15)11: ==26874==12: (null)13: ==26874== Invalid free() / delete / delete[]14: ==26874== at 0x4A04D72: free (vg_replace_malloc.c:325)15: ==26874== by 0x4005C1: main (core1.c:17)16: ==26874== Address 0x502a042 is 2 bytes inside a block of size 10 alloc‘d17: ==26874== at 0x4A0515D: malloc (vg_replace_malloc.c:195)18: ==26874== by 0x400565: main (core1.c:5)19: ==26874==20: ==26874==21: ==26874== HEAP SUMMARY:22: ==26874== in use at exit: 0 bytes in 0 blocks23: ==26874== total heap usage: 1 allocs, 2 frees, 10 bytes allocated24: ==26874==25: ==26874== All heap blocks were freed -- no leaks are possible26: ==26874==27: ==26874== For counts of detected and suppressed errors, rerun with: -v28: ==26874== Use --track-origins=yes to see where uninitialised values come from29: ==26874== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)

可以看到,valgrind提示在17行有一個Invalid Free()

6 Valgrind的優缺點

valgrind預設使用memcheck工具做記憶體監測。

6.1 Advantages

用valgrind監測記憶體流失,不用重新編譯應用程式,不用重新連結應用程式,不用對應用進程做任何修改。如果想查看詳細的出錯資訊,只需要在編譯時間加上-g選項。

6.2 Disadvantages

不管valgrind在使用memcheck工具監測記憶體時,它會接管應用程式,並且讀取應用程式可執行檔和庫檔案中的debug資訊來顯示詳細的出錯位置。當valgrind啟動後,應用 進程實際上在valgrind的虛擬環境中執行,valgrind會將每行代碼傳遞給memcheck工具,memcheck工具再加入自己的調試資訊,之後再將合成的代碼真正運行。memcheck工具在 應用進程每個防存操作和每個變數賦值操作時加入額外的統計代碼,通常情況下,使用memcheck工具後應用程式的已耗用時間會比原生代碼慢大約10-50倍。

其次,對於一些不停機啟動並執行伺服器程式的記憶體問題,valgrind無能為力。不僅僅是因為valgrind無法使之停止,還有可能是因為伺服器處理序本身就被設計為申請一些生命週期 與進程生命週期一樣長的記憶體,永遠不釋放,這些記憶體會被valgrind報泄漏錯誤。

再次,valgrind對多線程程式支援得不夠好。在多線程程式執行時,valgrind在同一時刻只讓其中一個線程執行,它不會充分利用多核的環境。在用valgrind運行您的多線程程式 時,您的寶貴程式的運行情況可能跟不使用valgrind的運行情況千差萬別。

7 Valgrind的其他工具

除了memcheck工具外,valgrind工具包還有一些別的好用的工具

7.1 Cachegrind

這個工具類比 CPU中的一級緩衝I1,D1和L2二級緩衝,能夠精確地指出程式中 cache的丟失和命中。如果需要,它還能夠為我們提供cache丟失次數,記憶體引用次數,以及每行 代碼,每個函數,每個模組,整個程式產生的指令數。這對最佳化程式有很大的協助。 詳情見這裡

7.2 Callgrind

Callgrind收集程式運行時的一些資料,函數調用關係等資訊,還可以有選擇地進行cache 類比。在運行結束時,它會把分析資料寫入一個檔案。callgrindannotate可以把 這個檔案的內容轉化成可讀的形式。 詳情見這裡

7.3 Helgrind

它主要用來檢查C/C++多線程程式(使用POSIX線程)中出現的同步問題。Helgrind 尋找記憶體中被多個線程訪問,而又沒有一貫加鎖的地區,這些地區往往是線程之間失去同 步的地方,而且會導致難以發掘的錯誤。Helgrind實現了名為"Eraser" 的競爭檢測演算法,並做了進一步改進,減少了報告錯誤的次數。 詳情見這裡

7.4 DRD

這也使一款多線程程式監測工具,它提供的監測資訊比Helgrind更豐富。 詳情見這裡

7.5 Massif

堆棧分析器,它能測配量序在堆棧中使用了多少記憶體。告訴我們堆塊,堆管理塊和棧的大小。對於那些被應用進程釋放但是還沒有交還給作業系統的記憶體,memcheck是監測 不出來的,而Massif能有效第監測到這類記憶體。 詳情見這裡

7.6 DHAT

這個工具能詳細地顯示應用進程如何使用堆棧,以使使用者更好地評估程式的設計。 詳情見這裡

8 參考
  • http://www.valgrind.org/

Author: Cobbliu

Created: 2015-04-14 Tue 01:19

Emacs 24.4.1 (Org mode 8.2.10)

Validate

 分類: C, C++, linux編程技術, linux系統技術

記憶體排查 valgrind

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.