目录
一、示例代码
二、DAM问题
三、使用Valgrind查看内存使用信息
四、工具安装与参考
一、实例代码
配书代码包Chapter_07/pg_222/memprobs.c
1 #include <malloc.h>
2 #include <stdio.h>
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 read
、before
、alloc'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 read
、inside
、free'd
;
Line: 16
的double free()
- 描述为
Invalid free() / delete / delete[] / realloc() ... Address 0x51fc040 is 0 bytes inside a block of size 12 free'd
- 这里有一行无效的释放,原因在于你释放了一块已经释放过的区域,重复释放
- 核心词是
Invalid free()
、inside
、free'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
- Memcheck: 所有类型的错误信息解释
4.2. Explanation of error messages from Memcheck
http://valgrind.org/docs/manual/mc-manual.html#mc-manual.errormsgs
- 官方 manual
- 应用 Valgrind 发现 Linux 程序的内存问题
使用书籍与相关笔记
[书籍]《软件调试的艺术》(《 The Art of Debugging with GDB, DDD, and Eclipse》)
https://www.jianshu.com/p/0805ba683126
网友评论