[Valgrind]检测动态分配的内存DAM(Dynamically Allocated Memory)

目录

一、示例代码
二、DAM问题
三、使用Valgrind查看内存使用信息
四、工具安装与参考

一、实例代码

配书代码包Chapter_07/pg_222/memprobs.c

1   #include 
2   #include 
3   
4   
5   
6   int main( void )
7   {
8       int *a = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
9       int *b = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
10  
11      for( int i = -1; i <= 3; ++i )
12          a[i] = i; // a bad write for i = -1 and 3.
13
14      free(a);
15      printf("%d\n", a[1]); // a read from freed memory
16      free(a); // a double free on pointer a.
17  
18      return 0; // program ends without freeing *b.
19  }

配书代码包Chapter_07/pg_222/Makefile

TARGET = memprobs
CC     = clang
CFLAGS = -g3 -Wall -Wextra -std=c99

all: $(TARGET)
.PHONY: clean

clean:
    $(RM) core $(TARGET)

run

$ ls
Makefile  memprobs.c

$ make memprobs
clang -g3 -Wall -Wextra -std=c99    memprobs.c   -o memprobs
memprobs.c:9:7: warning: unused variable 'b' [-Wunused-variable]
        int *b = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
             ^
1 warning generated.

$ ./memprobs
*** Error in `./memprobs': double free or corruption (out): 0x0000000000cbd010 ***
Aborted (core dumped)

二、DAM 问题

1、内存泄漏

  • 没有释放动态分配的内存,int *b指向的 3个int内存 始终没有得到释放;
  • 内存泄漏会不断消耗内存,造成程序可用的内存越来越少;
  • 当存在内存泄漏的程序终止时,有些操作系统会回收这些内存,有些则要等到系统重启才会回收;

2、对malloc()的调用失败

  • 解决方法:可以通过检测malloc()的返回值来检测;
  • 计算中的程序错误可能导致请求一个数值太大或者为负值的DAM(指malloc()的调用参数),造成调用失败;
  • 系统真的没有内存可用的时候,也会调用失败;

3、访问错误

  • DAM段之外的地址执读和写操作;
  • 释放DAM段之后,对DAM区域中的内存执行读写操作;

4、重复释放(double free)

  • 对动态内存的同一段调用两次free()

三、使用Valgrind查看内存使用信息

  • $ valgrind --tool=memcheck --leak-check=full ./memprobs
$ valgrind --tool=memcheck --leak-check=full ./memprobs
==4126== Memcheck, a memory error detector
==4126== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4126== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4126== Command: ./memprobs
==4126== 
==4126== Invalid write of size 4
==4126==    at 0x4005D4: main (memprobs.c:12)
==4126==  Address 0x51fc03c is 4 bytes before a block of size 12 alloc'd
==4126==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4126==    by 0x40059D: main (memprobs.c:8)
==4126== 
==4126== Invalid read of size 4
==4126==    at 0x4005FF: main (memprobs.c:15)
==4126==  Address 0x51fc044 is 4 bytes inside a block of size 12 free'd
==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4126==    by 0x4005F2: main (memprobs.c:14)
==4126== 
1
==4126== Invalid free() / delete / delete[] / realloc()
==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4126==    by 0x400614: main (memprobs.c:16)
==4126==  Address 0x51fc040 is 0 bytes inside a block of size 12 free'd
==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4126==    by 0x4005F2: main (memprobs.c:14)
==4126== 
==4126== 
==4126== HEAP SUMMARY:
==4126==     in use at exit: 12 bytes in 1 blocks
==4126==   total heap usage: 2 allocs, 2 frees, 24 bytes allocated
==4126== 
==4126== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
==4126==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4126==    by 0x4005B0: main (memprobs.c:9)
==4126== 
==4126== LEAK SUMMARY:
==4126==    definitely lost: 12 bytes in 1 blocks
==4126==    indirectly lost: 0 bytes in 0 blocks
==4126==      possibly lost: 0 bytes in 0 blocks
==4126==    still reachable: 0 bytes in 0 blocks
==4126==         suppressed: 0 bytes in 0 blocks
==4126== 
==4126== For counts of detected and suppressed errors, rerun with: -v
==4126== ERROR SUMMARY: 5 errors from 4 contexts (suppressed: 0 from 0)

错误信息分析

Line:12 第一次循环会访问a[-1] 越界数组

  • 描述为==4126== Invalid write of size 4 at 0x4005D4: main (memprobs.c:12) Address 0x51fc03c is 4 bytes before a block of size 12 alloc'd
  • 你访问的位置在一块分配好的12字节内存之前
  • 核心词是Invalid readbeforealloc'd

Line:15的访问错误,访问已经释放过的DAM段

  • 描述为Invalid read of size 4 at 0x4005FF: main (memprobs.c:15) Address 0x51fc044 is 4 bytes inside a block of size 12 free'd
  • 没错你访问了一块分配了12个字节的内存块,但是这个内存块已经被释放了free'd`
  • 核心词是Invalid readinsidefree'd

Line: 16double free()

  • 描述为Invalid free() / delete / delete[] / realloc() ... Address 0x51fc040 is 0 bytes inside a block of size 12 free'd
  • 这里有一行无效的释放,原因在于你释放了一块已经释放过的区域重复释放
  • 核心词是Invalid free()insidefree'd

Line:9的那个没有释放过的int *b

  • 描述为12 bytes in 1 blocks are definitely lost in loss record 1 of 1
  • 一个确定的内存泄露,12字节刚好就就是3个int
  • 核心词就是definitely lost

四、工具安装与参考

Valgrind

  • 安装
    sudo apt-get install valgrind

  • Quick Start

http://valgrind.org/docs/manual/quick-start.html

  • Memcheck: 所有类型的错误信息解释

4.2. Explanation of error messages from Memcheck
http://valgrind.org/docs/manual/mc-manual.html#mc-manual.errormsgs

  • 官方 manual

http://valgrind.org/docs/manual/manual.html

  • 应用 Valgrind 发现 Linux 程序的内存问题

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

使用书籍与相关笔记

[书籍]《软件调试的艺术》(《 The Art of Debugging with GDB, DDD, and Eclipse》)
https://www.jianshu.com/p/0805ba683126

你可能感兴趣的:([Valgrind]检测动态分配的内存DAM(Dynamically Allocated Memory))