使用valgrind检测内存问题

c272ce1c8c520cd5d6e2f55915f5d64b.png

valgrind是一款用于内存调试、内存泄漏检测以及性能分析的软件开发工具。

1

valgrind安装


可以到官网下载最新的源码包:valgrind官网下载,也可以直接使用 c_utils/debug/valgrind 目录提供的 valgrind-3.13.0.tar.bz2 源码包。

  1. 首先解压源码包

tar xjf valgrind-3.13.0.tar.bz2
  1. 进入解压目录,执行配置文件

cd valgrind-3.13.0/
./configure 
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether to enable maintainer-specific portions of Makefiles... no
checking whether ln -s works... yes
...
  1. 配置成功后执行make编译

make
  1. 安装即可

make install

2

内存泄漏检测


这是valgrind最常用一个小功能。程序如下,详见 c_utils/debug/valgrind/test1.c

84fe74c8ae9a81f480c228dcd2da7197.png

这是一段申请内存但是没有释放的程序,首先编译一下

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

34618905f227c1d92fa0aa24ff1f012e.png

这里我们忘记了对 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

13067b8474d1a63892db41313821c7b7.png

程序中分别存在栈越界和堆越界,很遗憾的是我们运行程序一切正常,只有极少数情况下是直接运行出内存错误的,这非常危险,但是有概率性。

$ ./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

973245081d1a910dbc6a026902418341.png

这是个动态分配和释放内存的过程,首先编译出可执行程序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 +----------------------------------------------------------------------->Mi
     0                                                                   0.998

Number of snapshots: 83
 Detailed 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            0
  1        102,636               24                4            20            0
  2        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            0
  4        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            0
  6        166,826           31,464            5,244        26,220            0
  7        179,370           37,608            6,268        31,340            0
  8        191,914           43,752            7,292        36,460            0
  9        204,458           49,896            8,316        41,580            0
 10        217,002           56,040            9,340        46,700            0
 11        229,546           62,184           10,364        51,820            0
 12        242,090           68,328           11,388        56,940            0
 13        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            0
 15        284,426           89,064           14,844        74,220            0
 16        296,970           95,208           15,868        79,340            0
 17        309,514          101,352           16,892        84,460            0
 18        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            0
 20        347,146          119,784           19,964        99,820            0
 21        359,690          125,928           20,988       104,940            0
 22        372,234          132,072           22,012       110,060            0
 23        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            0
 25        409,866          150,504           25,084       125,420            0
 26        422,410          156,648           26,108       130,540            0
 27        434,954          162,792           27,132       135,660            0
 28        447,498          168,936           28,156       140,780            0
 29        460,042          175,080           29,180       145,900            0
 30        472,586          181,224           30,204       151,020            0
 31        485,130          187,368           31,228       156,140            0
 32        497,674          193,512           32,252       161,260            0
 33        510,218          199,656           33,276       166,380            0
 34        522,762          205,800           34,300       171,500            0
 35        535,306          211,944           35,324       176,620            0
 36        547,850          218,088           36,348       181,740            0
 37        560,394          224,232           37,372       186,860            0
 38        572,938          230,376           38,396       191,980            0
 39        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            0
 41        618,850          226,824           37,804       189,020            0
 42        631,454          220,248           36,708       183,540            0
 43        644,058          213,672           35,612       178,060            0
 44        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            0
 46        681,870          193,944           32,324       161,620            0
 47        694,474          187,368           31,228       156,140            0
 48        707,078          180,792           30,132       150,660            0
 49        725,984          170,928           28,488       142,440            0
 50        735,690          165,864           27,644       138,220            0
 51        745,396          160,800           26,800       134,000            0
 52        755,102          155,736           25,956       129,780            0
 53        764,808          150,672           25,112       125,560            0
 54        774,514          145,608           24,268       121,340            0
 55        784,220          140,544           23,424       117,120            0
 56        793,926          135,480           22,580       112,900            0
 57        803,632          130,416           21,736       108,680            0
 58        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            0
 60        832,750          115,224           19,204        96,020            0
 61        842,456          110,160           18,360        91,800            0
 62        852,162          105,096           17,516        87,580            0
 63        861,868          100,032           16,672        83,360            0
 64        871,574           94,968           15,828        79,140            0
 65        881,280           89,904           14,984        74,920            0
 66        890,986           84,840           14,140        70,700            0
 67        900,692           79,776           13,296        66,480            0
 68        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            0
 70        929,810           64,584           10,764        53,820            0
 71        939,516           59,520            9,920        49,600            0
 72        949,222           54,456            9,076        45,380            0
 73        958,928           49,392            8,232        41,160            0
 74        968,634           44,328            7,388        36,940            0
 75        978,340           39,264            6,544        32,720            0
 76        988,046           34,200            5,700        28,500            0
 77        997,752           29,136            4,856        24,280            0
 78      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            0
 80      1,026,870           13,944            2,324        11,620            0
 81      1,036,576            8,880            1,480         7,400            0
 82      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 install

make 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」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

6033e4f7d4d8c2549acf03814f106126.png

嵌入式Linux

微信扫描二维码,关注我的公众号

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值