Linux 基于valgrind分析内存泄漏
1.valgrind工具
通过以下命令查看valgrind工具是否安装,以及安装的版本:
zl@zl-VirtualBox:~/vstdio-workspace/memoryout-test/build$ valgrind --version
valgrind-3.13.0
zl@zl-VirtualBox:~/vstdio-workspace/memoryout-test/build$
如果提示命令没找到,那可能是环境变量不对,或者是没有安装,x86的Linux系统上安装都比较简单,直接通过命令就可以;arm Linux上可能需要重新编译文件系统或者是交叉编译valgrind源码包。
2.命令
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --undef-value-errors=no --log-file=./memory-test_valgrind_report-1.log ./memory-test
2.1命令分析
- —tool=memcheck: 使用 memcheck 工具检测内存错误,包括使用未初始化的变量、读写越界等。
- —leak-check=full: 全面检测内存泄漏,不仅仅检测未释放的内存,还会检测处理时出现的一些问题。
- —show-leak-kinds=all: 显示所有的内存泄漏信息。
- —undef-value-errors=no: 不检查未定义的值错误。
- —log-file=./test.log: 将日志信息输出到 log 文件中。
- ./memory-test:要测试的可执行文件
执行完之后我们便可以看到在文件夹内生成一个名为test.log的文件,文件中便是内存信息。
2.2输出日志说明
比如,我们检测内存泄漏的时候拿到了如下内容的log日志:
==6048== Memcheck, a memory error detector
==6048== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6048== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6048== Command: ./memoryout-test
==6048== Parent PID: 2379
==6048==
==6048==
==6048== HEAP SUMMARY:
==6048== in use at exit: 1,024 bytes in 1 blocks
==6048== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==6048==
==6048== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6048== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6048== by 0x108735: main (memoryout-test.c:33)
==6048==
==6048== LEAK SUMMARY:
==6048== definitely lost: 1,024 bytes in 1 blocks
==6048== indirectly lost: 0 bytes in 0 blocks
==6048== possibly lost: 0 bytes in 0 blocks
==6048== still reachable: 0 bytes in 0 blocks
==6048== suppressed: 0 bytes in 0 blocks
==6048==
==6048== For counts of detected and suppressed errors, rerun with: -v
==6048== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
分析每一行的含义:
==6048== Memcheck, a memory error detector
这句话是 Valgrind 内存检查器的标识。
==6048== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
这是版权信息,显示了 Valgrind 的作者和版权信息。
==6048== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
这句话告诉您正在使用哪个版本的 Valgrind 和哪个库(LibVEX)。
==6048== Command: ./memoryout-test
这句话显示了启动程序的命令。
==6048== Parent PID: 2379
这句话显示了父进程的进程 ID。
==6048==
==6048==
这是空行,用于分割段落。
==6048== HEAP SUMMARY:
这句话开始了对堆内存的摘要。
==6048== in use at exit: 1,024 bytes in 1 blocks
这句话显示在程序退出时还有多少字节的堆内存处于使用状态。
==6048== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
这句话显示了程序总共分配了多少字节的堆内存,包括其中被释放的和未被释放的。
==6048==
这又是一个空行,用于分割段落。
==6048== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6048== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6048== by 0x108735: main (memoryout-test.c:33)
这句话告诉您哪个内存块被泄漏,并提供了分配该内存块的函数和文件。在这个例子中,它显示了在程序的第33行中使用了 malloc 来分配一个内存块,在程序退出时未释放该内存块。
==6048==
这又是一个空行,用于分割段落。
==6048== LEAK SUMMARY:
这句话开始了对泄漏情况的摘要。
==6048== definitely lost: 1,024 bytes in 1 blocks
这句话指出了存在明确的内存泄漏,即分配的 1024 字节内存块在程序退出时未被释放。
==6048== indirectly lost: 0 bytes in 0 blocks
这句话指出了间接的内存泄漏,即分配的内存块的指针丢失了,程序无法再次释放该内存块。
==6048== possibly lost: 0 bytes in 0 blocks
这句话指出可能存在泄漏,但是 Valgrind 无法确定。
==6048== still reachable: 0 bytes in 0 blocks
这句话显示程序仍然可以访问的内存块的大小,即仍处于程序控制下的内存块。
==6048== suppressed: 0 bytes in 0 blocks
这句话显示已被抑制的错误和泄漏数量。
==6048==
这又是一个空行,用于分割段落。
==6048== For counts of detected and suppressed errors, rerun with: -v
这句话提供有关检测到的错误和被抑制的错误数量的信息。如果需要更详细的信息,请使用 -v 参数再次运行 Valgrind。
==6048== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
这句话告诉您在多少上下文中检测到了多少个错误,在本例中,检测到了1个内存泄漏的错误。
3.内存泄漏
valgrind 将内存泄漏分为 4 类:
- 明确泄漏(definitely lost):内存还没释放,但已经没有指针指向内存,内存已经不可访问。
- 间接泄漏(indirectly lost):泄漏内存指针保存在明确泄漏内存中,随着明确泄漏内存不可访问,导致间接泄漏内存也不可访问。
- 可能泄漏(possibly lost):指针并不指向内存头地址,而是指向内存内部的位置。
- 仍可访达(still reachable):指针一直存在且指向内存头部,直至程序退出时内存还没释放。
下面详细看下每一类泄漏的实例以及抓取到的日子log:
3.1明确泄漏(definitely lost)
1.实例源码:
int main(int argc, char **argv)
{
char *buf = NULL;
buf = (char *)malloc(1024);
if (buf == NULL)
{
perror("malloc failed");
}
return 0;
}
2.valgrind抓取的日志:
==26343== Memcheck, a memory error detector
==26343== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==26343== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==26343== Command: ./memoryout-test
==26343== Parent PID: 26233
==26343==
==26343==
==26343== HEAP SUMMARY:
==26343== in use at exit: 1,024 bytes in 1 blocks
==26343== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==26343==
==26343== 1,024 bytes in 1 blocks are definitely lost in loss record 1 of 1
==26343== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==26343== by 0x1086AA: main (memoryout-test.c:10)
==26343==
==26343== LEAK SUMMARY:
==26343== definitely lost: 1,024 bytes in 1 blocks
==26343== indirectly lost: 0 bytes in 0 blocks
==26343== possibly lost: 0 bytes in 0 blocks
==26343== still reachable: 0 bytes in 0 blocks
==26343== suppressed: 0 bytes in 0 blocks
==26343==
==26343== For counts of detected and suppressed errors, rerun with: -v
==26343== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
3.分析:
该类泄漏,程序已经失去了对申请的内存的操作能力,所以这类是必须要改掉的。
3.2间接泄漏(indirectly lost)
1.实例源码:
struct people
{
char *name;
};
int main(int argc, char **argv)
{
struct people *one;
one = (struct people *)malloc(sizeof(struct people));
if (one == NULL)
{
perror("malloc failed");
}
one->name = (char *)malloc(64);
if (one->name == NULL)
{
perror("malloc failed");
}
one = NULL;
return 0;
}
2.valgrind抓取的日志:
==31693== Memcheck, a memory error detector
==31693== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31693== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31693== Command: ./memoryout-test
==31693== Parent PID: 26233
==31693==
==31693==
==31693== HEAP SUMMARY:
==31693== in use at exit: 72 bytes in 2 blocks
==31693== total heap usage: 2 allocs, 0 frees, 72 bytes allocated
==31693==
==31693== 64 bytes in 1 blocks are indirectly lost in loss record 1 of 2
==31693== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==31693== by 0x1086C3: main (memoryout-test.c:21)
==31693==
==31693== 72 (8 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==31693== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==31693== by 0x1086A2: main (memoryout-test.c:15)
==31693==
==31693== LEAK SUMMARY:
==31693== definitely lost: 8 bytes in 1 blocks
==31693== indirectly lost: 64 bytes in 1 blocks
==31693== possibly lost: 0 bytes in 0 blocks
==31693== still reachable: 0 bytes in 0 blocks
==31693== suppressed: 0 bytes in 0 blocks
==31693==
==31693== For counts of detected and suppressed errors, rerun with: -v
==31693== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
3.分析:
one指针变量直接置空,导致申请的8 bytes大小的内存确定泄漏,也就是这个是明确泄漏。而one的置空,导致了name赋值的64 bytes的内存也无法访问了,所以这64bytes是间接泄漏的。间接泄漏内存也得修改,但是优先修改导致其泄漏的明确泄漏。
3.3可能泄漏(possibly lost)
1.实例源码:
char *buffer = NULL;
int main(int argc, char **argv)
{
buffer = (char *)malloc(1024);
if (buffer == NULL)
{
perror("malloc failed");
}
buffer++;
return 0;
}
2.valgrind抓取的日志:
==8937== Memcheck, a memory error detector
==8937== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8937== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==8937== Command: ./memoryout-test
==8937== Parent PID: 26233
==8937==
==8937==
==8937== HEAP SUMMARY:
==8937== in use at exit: 1,024 bytes in 1 blocks
==8937== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==8937==
==8937== 1,024 bytes in 1 blocks are possibly lost in loss record 1 of 1
==8937== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8937== by 0x1086A2: main (memoryout-test.c:54)
==8937==
==8937== LEAK SUMMARY:
==8937== definitely lost: 0 bytes in 0 blocks
==8937== indirectly lost: 0 bytes in 0 blocks
==8937== possibly lost: 1,024 bytes in 1 blocks
==8937== still reachable: 0 bytes in 0 blocks
==8937== suppressed: 0 bytes in 0 blocks
==8937==
==8937== For counts of detected and suppressed errors, rerun with: -v
==8937== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
3.分析:
valgrind 之所以会怀疑可能泄漏,是因为指针已经偏移,并没有指向内存头,而是有内存偏移,指向内存内部的位置。 可能泄漏需要具体分析,比如实例中是因为使用了++操作,确认不是功能需要的修改之后,重新修改,指向内存头,然后再进一步分析。
3.4仍可访达(still reachable)
1.实例源码:
char *buffer = NULL;
int main(int argc, char **argv)
{
buffer = (char *)malloc(1024);
if (buffer == NULL)
{
perror("malloc failed");
}
return 0;
}
2.valgrind抓取的日志:
==10960== Memcheck, a memory error detector
==10960== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10960== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10960== Command: ./memoryout-test
==10960== Parent PID: 26233
==10960==
==10960==
==10960== HEAP SUMMARY:
==10960== in use at exit: 1,024 bytes in 1 blocks
==10960== total heap usage: 1 allocs, 0 frees, 1,024 bytes allocated
==10960==
==10960== 1,024 bytes in 1 blocks are still reachable in loss record 1 of 1
==10960== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10960== by 0x1086A2: main (memoryout-test.c:71)
==10960==
==10960== LEAK SUMMARY:
==10960== definitely lost: 0 bytes in 0 blocks
==10960== indirectly lost: 0 bytes in 0 blocks
==10960== possibly lost: 0 bytes in 0 blocks
==10960== still reachable: 1,024 bytes in 1 blocks
==10960== suppressed: 0 bytes in 0 blocks
==10960==
==10960== For counts of detected and suppressed errors, rerun with: -v
==10960== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
3.分析:
仍可访达 表示在程序退出时,不管是正常退出还是异常退出,内存申请了没释放,都属于仍可访达的泄漏类型。
如果测试的程序是正常退出的,那么这些仍可访达的内存就是泄漏,最好修复了。
如果测试是长期运行的程序,通过信号提前终止,那么这些内存就大概率并不是泄漏。
所以说这种情况也需要具体分析一下,比如上面的实例,是正常的退出,程序已经执行完,这个时候仍可访达也需要修改,手动释放掉。如果是一个线程,长期运行,为了抓取valgrind日志才通过信号终止的,这个时候根据日志确定没有释放的内存是正常情况,还是异常情况。
4.总结
如果通过valgrind抓取的日志中,出现了四类内存泄漏中的任何一种,都应该引起重视,根据日志中显示的详细信息,分析出现的内存泄漏是属于正常情况,也就是功能需要,还是异常情况,需要修改掉。另外,一定要注意,并不是valgrind抓取的日志中没有任何泄漏就说明是正常的,还需要结合程序实际运行的情况,以其他工具辅助,比如top,分析程序是不是在不断申请内存。因为有时候valgrind抓取的日志是通过信号中止了线程之后抓取的,这个时候可能隐藏程序运行过程中的问题,比如:我就碰到一种情况,烧机借助top发现程序占的内存在不断增加,直到耗尽设备内存被kill掉,但是我通过信号中止程序抓取的log中并没有提示内存泄漏,最后排查是信号中止之后线程退出,在退出后面的处理中,将线程内申请的可访达的内存都释放掉了,所以导致抓取不到内存使用异常。
- 分享
- 举报
-
浏览量:738次2023-12-06 09:40:25
-
浏览量:716次2024-01-09 08:52:25
-
浏览量:4891次2021-03-26 15:39:50
-
浏览量:749次2024-01-25 15:08:45
-
浏览量:4717次2021-04-02 15:26:31
-
浏览量:6555次2021-04-15 14:30:22
-
浏览量:2277次2020-03-18 14:29:31
-
浏览量:9380次2018-10-24 14:39:45
-
浏览量:3310次2020-08-17 19:59:15
-
浏览量:1147次2023-07-05 10:18:06
-
浏览量:10543次2020-11-13 14:17:48
-
浏览量:899次2023-10-26 13:41:10
-
浏览量:1613次2023-10-26 13:56:58
-
浏览量:156次2023-08-30 15:38:33
-
浏览量:1853次2022-05-30 09:56:07
-
浏览量:2306次2019-12-31 09:01:27
-
浏览量:6316次2021-03-29 11:34:27
-
浏览量:2764次2017-11-20 16:03:39
-
浏览量:2683次2023-10-17 17:23:21
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
林
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明