0%

【Linux技术分享】Valgrind检测内存泄露的学习和使用

Valgrind的学习和使用

Valgrind 是一个 GPL 系统,用于调试和分析 Linux 程序。使用 Valgrind 的 工具,可以自动检测许多内存管理和线程错误。

软件安装

  1. uos/debian/ubuntu

    sudo apt install valgrind

  2. 源码安装

    官网http://www.valgrind.org

    图1

    ./autogen.sh

    ./configure

    make && install

实现逻辑

  1. 内存泄露主要使用Memcheck,官网介绍

    图2

解释:

  • 建立表来存储进程的地址空间,当要读写内存某个字节时,首先检查对此字节对应表的A bit,如果不存在,memcheck 则报告读写错误
  • 内核(core)类似于一个虚拟的 CPU 环境,这样当内存中的某个字节被加载到真实的 CPU 中时,该字节对应的 V bit (在 valid-value map 中) 也被加载到虚拟的 CPU 环境中。一旦寄存器中的值,被用来产生内存地址,或者该值能够影响程序输出,则 memcheck 会检查对应的 V bits,如果该值尚未初始化,则会报告使用未初始化内存错误

使用

example1:内存未释放

valgrind –leak-check=yes ./main

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
#include<stdlib.h>

void func()
{
char *p = malloc(sizeof(char));//未释放
}

int main()
{
func();
return 0;
}

输出结果为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
==19112== Memcheck, a memory error detector
==19112== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19112== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==19112== Command: ./main
==19112==
==19112==
==19112== HEAP SUMMARY:
==19112== in use at exit: 1 bytes in 1 blocks
==19112== total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==19112==
==19112== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19112== at 0x483577F: malloc (vg_replace_malloc.c:299)
==19112== by 0x401133: func (in /home/mecry/dde-c/metho/metho1/main)
==19112== by 0x401148: main (in /home/mecry/dde-c/metho/metho1/main)
==19112==
==19112== LEAK SUMMARY:
==19112== definitely lost: 1 bytes in 1 blocks
==19112== indirectly lost: 0 bytes in 0 blocks
==19112== possibly lost: 0 bytes in 0 blocks
==19112== still reachable: 0 bytes in 0 blocks
==19112== suppressed: 0 bytes in 0 blocks
==19112==
==19112== For counts of detected and suppressed errors, rerun with: -v
==19112== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

终端输出很清楚,一次获取新内存,0次释放,共有0字节为释放,然后就自动定位你未释放的地方==19112== at 0x483577F: malloc (vg_replace_malloc.c:299)这句话不用看,是c底层库的东西==19112== by 0x401133: func (in /home/mecry/dde-c/metho/metho1/main)这句直接指明是func()函数有内存泄露

1
2
3
4
5
6
7
8
==19112== HEAP SUMMARY:
==19112== in use at exit: 1 bytes in 1 blocks
==19112== total heap usage: 1 allocs, 0 frees, 1 bytes allocated
==19112==
==19112== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19112== at 0x483577F: malloc (vg_replace_malloc.c:299)
==19112== by 0x401133: func (in /home/mecry/dde-c/metho/metho1/main)
==19112== by 0x401148: main (in /home/mecry/dde-c/metho/metho1/main)

example1:越界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<stdio.h>
#include<stdlib.h>

void func()
{
int *a = (int*)malloc(sizeof(int));
a[0] = 1;
free(a);

a[0] = 1; //已释放再定义
free(a); //已释放再释放

}

int main()
{
func();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
==27268== Memcheck, a memory error detector
==27268== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==27268== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==27268== Command: ./main
==27268==
==27268== Invalid write of size 4
==27268== at 0x401162: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Address 0x4a31040 is 0 bytes inside a block of size 4 free'd
==27268== at 0x48369AB: free (vg_replace_malloc.c:530)
==27268== by 0x40115D: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Block was alloc'd at
==27268== at 0x483577F: malloc (vg_replace_malloc.c:299)
==27268== by 0x401143: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268==
==27268== Invalid free() / delete / delete[] / realloc()
==27268== at 0x48369AB: free (vg_replace_malloc.c:530)
==27268== by 0x401173: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Address 0x4a31040 is 0 bytes inside a block of size 4 free'd
==27268== at 0x48369AB: free (vg_replace_malloc.c:530)
==27268== by 0x40115D: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Block was alloc'd at
==27268== at 0x483577F: malloc (vg_replace_malloc.c:299)
==27268== by 0x401143: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268==
==27268==
==27268== HEAP SUMMARY:
==27268== in use at exit: 0 bytes in 0 blocks
==27268== total heap usage: 1 allocs, 2 frees, 4 bytes allocated
==27268==
==27268== All heap blocks were freed -- no leaks are possible
==27268==
==27268== For counts of detected and suppressed errors, rerun with: -v
==27268== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

写入未定义的四个字节

1
2
3
4
5
==27268== Invalid write of size 4
==27268== at 0x401162: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Address 0x4a31040 is 0 bytes inside a block of size 4 fre
e'd

释放未定义的四个字节

1
2
3
4
5
==27268== Invalid free() / delete / delete[] / realloc()
==27268== at 0x48369AB: free (vg_replace_malloc.c:530)
==27268== by 0x401173: func (in /home/mecry/dde-c/metho/metho2/main)
==27268== by 0x401184: main (in /home/mecry/dde-c/metho/metho2/main)
==27268== Address 0x4a31040 is 0 bytes inside a block of size 4 free'd