使用valgrind检测内存问题
valgrind是一款用于內存調試、內存泄漏檢測以及性能分析的軟件開發工具。
1
valgrind安裝
可以到官網下載最新的源碼包:valgrind官網下載,也可以直接使用?c_utils/debug/valgrind?目錄提供的?valgrind-3.13.0.tar.bz2?源碼包。
首先解壓源碼包
進入解壓目錄,執行配置文件
配置成功后執行make編譯
安裝即可
2
內存泄漏檢測
這是valgrind最常用一個小功能。程序如下,詳見?c_utils/debug/valgrind/test1.c
這是一段申請內存但是沒有釋放的程序,首先編譯一下
gcc test1.c -g -o test1然后我們使用valgrind工具進行檢測
$ valgrind --tool=memcheck --leak-check=full ./test1==2473== Memcheck, a memory error detector ==2473== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==2473== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==2473== Command: ./test1 ==2473== ==2473== ==2473== HEAP SUMMARY: ==2473== in use at exit: 100 bytes in 1 blocks ==2473== total heap usage: 1 allocs, 0 frees, 100 bytes allocated ==2473== ==2473== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==2473== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299) ==2473== by 0x40053E: main (test1.c:6) ==2473== ==2473== LEAK SUMMARY: ==2473== definitely lost: 100 bytes in 1 blocks ==2473== indirectly lost: 0 bytes in 0 blocks ==2473== possibly lost: 0 bytes in 0 blocks ==2473== still reachable: 0 bytes in 0 blocks ==2473== suppressed: 0 bytes in 0 blocks ==2473== ==2473== For counts of detected and suppressed errors, rerun with: -v ==2473== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)從HEAP SUMMARY下面可以清楚看到提示在test1.c文件的第6行,main函數中有100個字節的空間申請但是未釋放。注意只有編譯時候加了-g選項才能看到行號文件等信息。
3
誤用未初始化變量檢測
程序如下,詳見?c_utils/debug/valgrind/test2.c
這里我們忘記了對?condition?變量進行初始化,就使用了此變量,首先編譯一下
gcc test2.c -g -o test2然后我們使用valgrind工具進行檢測
$ valgrind ./test2==5814== Memcheck, a memory error detector ==5814== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==5814== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==5814== Command: ./test2 ==5814== ==5814== Conditional jump or move depends on uninitialised value(s) ==5814== at 0x400539: main (test2.c:8)提示main (test2.c:8)使用了未初始化的變量作為條件判斷依據。
4
內存訪問越界檢測
程序如下,詳見?c_utils/debug/valgrind/test3.c
程序中分別存在棧越界和堆越界,很遺憾的是我們運行程序一切正常,只有極少數情況下是直接運行出內存錯誤的,這非常危險,但是有概率性。
$ ./test3 buf[0] = a buf[1] = b buf[2] = c buf[3] = d buf[4] = e x[10] = a首先比下面使用valgrind進行檢測
$ valgrind ./test3==8528== Invalid write of size 1 ==8528== at 0x40064F: main (test3.c:15) ==8528== Address 0x520448a is 0 bytes after a block of size 10 alloc'd ==8528== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299) ==8528== by 0x400642: main (test3.c:14) ==8528== ==8528== Invalid read of size 1 ==8528== at 0x40065A: main (test3.c:16) ==8528== Address 0x520448a is 0 bytes after a block of size 10 alloc'd ==8528== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299) ==8528== by 0x400642: main (test3.c:14) ==8528==可以看到檢測到了14-16行的堆越界訪問問題,?但是遺憾的是并未檢測到9-12行的棧越界問題,所以valgrind是不能檢測到靜態內存問題的
5
massif工具使用
有時候我們的程序比較復雜,沒辦法很直觀的分析出內存使用情況,這時候可以使用valgrind的massif工具來進行動態分析,通過不斷的取程序堆的快照來達到監視程序內存分配的目的。程序如下,詳見?c_utils/debug/valgrind/test4.c
這是個動態分配和釋放內存的過程,首先編譯出可執行程序test4,然后使用massif工具進行檢測,方法如下
$ valgrind --tool=massif ./test4這里必須指定工具massif,輸出信息并沒有可用信息
==10727== Massif, a heap profiler ==10727== Copyright (C) 2003-2017, and GNU GPL'd, by Nicholas Nethercote ==10727== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==10727== Command: ./test4 ==10727== ==10727==但是此時使用ls命令會發現當前目錄下已經產生了一個名為massif.out.XXX的文件。使用ms_print輸出文件分析信息。
ms_print massif.out.10727如果輸出信息過多,可重定向到文件
ms_print massif.out.10727 > log.txt查看log.txt內容
-------------------------------------------------------------------------------- Command: ./test4 Massif arguments: (none) ms_print arguments: massif.out.10727 --------------------------------------------------------------------------------KB 234.4^ # | :#: | :::#::: | :::::#::::@ | ::::::#::::@: | ::::::::#::::@::: | ::::::::::#::::@:::: | :::::::::::#::::@:::::: | :::::::::::::#::::@:::::::: | :@:::::::::::::#::::@::::::::: | ::@:::::::::::::#::::@:::::::::@: | :::@:::::::::::::#::::@:::::::::@:: | :@:::@:::::::::::::#::::@:::::::::@:::: | :::@:::@:::::::::::::#::::@:::::::::@:::::: | @::::@:::@:::::::::::::#::::@:::::::::@::::::@ | ::@::::@:::@:::::::::::::#::::@:::::::::@::::::@: | :::@::::@:::@:::::::::::::#::::@:::::::::@::::::@::: | :::::@::::@:::@:::::::::::::#::::@:::::::::@::::::@::::: | :::::::@::::@:::@:::::::::::::#::::@:::::::::@::::::@::::::@ | @:::::::@::::@:::@:::::::::::::#::::@:::::::::@::::::@::::::@: 0 +----------------------------------------------------------------------->Mi0 0.998Number of snapshots: 83Detailed snapshots: [2, 4, 13, 18, 23, 39 (peak), 44, 58, 68, 78]--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------0 0 0 0 0 01 102,636 24 4 20 02 112,338 4,776 796 3,980 0 16.67% (796B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (796B) 0x4005E6: func (test4.c:6)->16.67% (796B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------3 124,882 10,920 1,820 9,100 04 141,738 19,176 3,196 15,980 0 16.67% (3,196B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (3,196B) 0x4005E6: func (test4.c:6)->16.67% (3,196B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------5 154,282 25,320 4,220 21,100 06 166,826 31,464 5,244 26,220 07 179,370 37,608 6,268 31,340 08 191,914 43,752 7,292 36,460 09 204,458 49,896 8,316 41,580 010 217,002 56,040 9,340 46,700 011 229,546 62,184 10,364 51,820 012 242,090 68,328 11,388 56,940 013 259,338 76,776 12,796 63,980 0 16.67% (12,796B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (12,796B) 0x4005E6: func (test4.c:6)->16.67% (12,796B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------14 271,882 82,920 13,820 69,100 015 284,426 89,064 14,844 74,220 016 296,970 95,208 15,868 79,340 017 309,514 101,352 16,892 84,460 018 322,058 107,496 17,916 89,580 0 16.67% (17,916B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (17,916B) 0x4005E6: func (test4.c:6)->16.67% (17,916B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------19 334,602 113,640 18,940 94,700 020 347,146 119,784 19,964 99,820 021 359,690 125,928 20,988 104,940 022 372,234 132,072 22,012 110,060 023 384,778 138,216 23,036 115,180 0 16.67% (23,036B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (23,036B) 0x4005E6: func (test4.c:6)->16.67% (23,036B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------24 397,322 144,360 24,060 120,300 025 409,866 150,504 25,084 125,420 026 422,410 156,648 26,108 130,540 027 434,954 162,792 27,132 135,660 028 447,498 168,936 28,156 140,780 029 460,042 175,080 29,180 145,900 030 472,586 181,224 30,204 151,020 031 485,130 187,368 31,228 156,140 032 497,674 193,512 32,252 161,260 033 510,218 199,656 33,276 166,380 034 522,762 205,800 34,300 171,500 035 535,306 211,944 35,324 176,620 036 547,850 218,088 36,348 181,740 037 560,394 224,232 37,372 186,860 038 572,938 230,376 38,396 191,980 039 593,642 240,000 40,000 200,000 0 16.67% (40,000B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (40,000B) 0x4005E6: func (test4.c:6)->16.67% (40,000B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------40 606,246 233,400 38,900 194,500 041 618,850 226,824 37,804 189,020 042 631,454 220,248 36,708 183,540 043 644,058 213,672 35,612 178,060 044 656,662 207,096 34,516 172,580 0 16.67% (34,516B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (34,516B) 0x4005E6: func (test4.c:6)->16.67% (34,516B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------45 669,266 200,520 33,420 167,100 046 681,870 193,944 32,324 161,620 047 694,474 187,368 31,228 156,140 048 707,078 180,792 30,132 150,660 049 725,984 170,928 28,488 142,440 050 735,690 165,864 27,644 138,220 051 745,396 160,800 26,800 134,000 052 755,102 155,736 25,956 129,780 053 764,808 150,672 25,112 125,560 054 774,514 145,608 24,268 121,340 055 784,220 140,544 23,424 117,120 056 793,926 135,480 22,580 112,900 057 803,632 130,416 21,736 108,680 058 813,338 125,352 20,892 104,460 0 16.67% (20,892B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (20,892B) 0x4005E6: func (test4.c:6)->16.67% (20,892B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------59 823,044 120,288 20,048 100,240 060 832,750 115,224 19,204 96,020 061 842,456 110,160 18,360 91,800 062 852,162 105,096 17,516 87,580 063 861,868 100,032 16,672 83,360 064 871,574 94,968 15,828 79,140 065 881,280 89,904 14,984 74,920 066 890,986 84,840 14,140 70,700 067 900,692 79,776 13,296 66,480 068 910,398 74,712 12,452 62,260 0 16.67% (12,452B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (12,452B) 0x4005E6: func (test4.c:6)->16.67% (12,452B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------69 920,104 69,648 11,608 58,040 070 929,810 64,584 10,764 53,820 071 939,516 59,520 9,920 49,600 072 949,222 54,456 9,076 45,380 073 958,928 49,392 8,232 41,160 074 968,634 44,328 7,388 36,940 075 978,340 39,264 6,544 32,720 076 988,046 34,200 5,700 28,500 077 997,752 29,136 4,856 24,280 078 1,007,458 24,072 4,012 20,060 0 16.67% (4,012B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->16.67% (4,012B) 0x4005E6: func (test4.c:6)->16.67% (4,012B) 0x400648: main (test4.c:23)--------------------------------------------------------------------------------n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) --------------------------------------------------------------------------------79 1,017,164 19,008 3,168 15,840 080 1,026,870 13,944 2,324 11,620 081 1,036,576 8,880 1,480 7,400 082 1,046,282 3,816 636 3,180 0從分析信息中可以動態看到隨著時間變化,程序那些地方占用內存較多。
6
開發板上使用valgrind
如果程序只能運行在開發板上,那么此時如果想用valgrind工具,那么只能交叉編譯,然后放到開發板上運行。這里只簡單羅列下編譯過程:
tar xjf valgrind-3.13.0.tar.bz2 cd valgrind-3.13.0/ mkdir install ./configure --host=arm-linux --prefix=$PWD/install make make installmake install?以后在?install/bin?目錄中就可以看到生成的可執行文件
valgrind-3.13.0/install/bin$ ls callgrind_annotate cg_annotate cg_merge valgrind valgrind-listener callgrind_control cg_diff ms_print valgrind-di-server vgdb拷貝開發板運行即可。
筆者在開發板調試過程中并未遇到網上提到安裝目錄必須和開發板目錄一致導致的問題,反倒在運行時候遇到了如下錯誤提示:
valgrind: Fatal error at startup: a function redirection valgrind: which is mandatory for this platform-tool combination valgrind: cannot be set up. Details of the redirection are: valgrind: valgrind: A must-be-redirected function valgrind: whose name matches the pattern: strcmp valgrind: in an object with soname matching: ld-linux-armhf.so.3 valgrind: was not found whilst processing valgrind: symbols from the object with soname: ld-linux-armhf.so.3 valgrind: valgrind: Possible fixes: (1, short term): install glibc's debuginfo valgrind: package on this machine. (2, longer term): ask the packagers valgrind: for your Linux distribution to please in future ship a non- valgrind: stripped ld.so (or whatever the dynamic linker .so is called) valgrind: that exports the above-named function using the standard valgrind: calling conventions for this platform. The package you need valgrind: to install for fix (1) is called valgrind: valgrind: On Debian, Ubuntu: libc6-dbg valgrind: On SuSE, openSuSE, Fedora, RHEL: glibc-debuginfo valgrind: valgrind: Note that if you are debugging a 32 bit process on a valgrind: 64 bit system, you will need a corresponding 32 bit debuginfo valgrind: package (e.g. libc6-dbg:i386). valgrind: valgrind: Cannot continue -- exiting now. Sorry.參考此文章解決:Valgrind for ARM with Linaro Toolchain requiring libc6-dbg with Buildroot
因為筆者開發板庫使用strip命令裁剪過,所以只要保證文件系統?/lib?下的庫使用未裁剪過的即可。
筆者追蹤后發現是./ld-linux-armhf.so.3 -> ld-2.21.so這個庫問題,只需要從交叉編譯器拷貝原始未被裁剪過的庫替換開發板里的即可解決。
另生成的部分工具不是都在ARM板上運行的,比如上面的ms_print實際上是一個Perl腳本,運行前可使用?file?命令來確定在哪執行,這里不再一一介紹。
END
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識小密圈
關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。
歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~
嵌入式Linux
微信掃描二維碼,關注我的公眾號
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的使用valgrind检测内存问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海康威视多摄像头视频实时采集——Open
- 下一篇: IAR(8.324)---安装教程