valgrind 内存泄漏_Valgrind快速入门指南

介绍

Valgrind工具套件提供了许多调试和分析工具一遍使得你的程序运行的更快和更加正确。这些工具中最有名的是被称为Memcheck的工具。它可以侦测许多内存相关的错误,而这些错误在C和C++是非常普遍的,并且会导致crash和不可预测的行为/结果。

准备你的程序

当你编译程序时请使用 “-g"以包含调试信息,以便Memcheck错误信息可以精确包含代码行数。如果你可以忍受程序运行的缓慢,使用-O0也是一个好主意。虽然总的来说在以-O1编译的代码上运行Memcheck的效果很好而且运行速度的改善相当不错,但错误信息可能会不准确。,这里需要注意的是使用-O2以及更高的编译选项是不推荐的,因为Memcheck偶尔会报告一些根本不存在的为初始化错误。

用Mencheck运行你的程序

如果你正常情况下是这样运行你的程序的:

myprog arg1 arg2

那么我们就该使用如下命令行:

valgrind --leak-check=yes myprog arg1 arg2

Memcheck是一个默认的工具。--leak-check选项打开了内存泄漏的侦测器。

你的程序会比正常情况下运行的更加缓慢,并且使用更多的内存,Memcheck会报告它侦测到的有关内存错误和泄漏的信息。

Memcheck的输出解释

下面是一个作为示例的C语言程序,它有内存错误和内存泄漏的问题。

9053cc1f03051accbbc9329e4951f430.png
2f514e144bb720506a26118182be35ce.png

运行valgrind后

13088f43a200f94a6acc8e31246b580c.png

会出现如下的信息,也就是上图中的problem 1: the heap block overrun:

==12402== Invalid write of size 4

==12402== at 0x108668: f (a.c:7)

==12402== by 0x108679: main (a.c:13)

==12402== Address 0x522d068 is 0 bytes after a block of size 40 alloc'd

==12402== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==12402== by 0x10865B: f (a.c:6)

==12402== by 0x108679: main (a.c:13)

这里需要注意的是:

  • 每条信息都包含了很多信息,请认真读取
  • 12402是一个进程ID,通常不是很重要
  • 第一行("Invalid write...")是告诉你这个什么类型的错误。在这里,程序因为heap block overrun而往其并没有的内存中写入信息。
  • 在第一行下面的信息是堆栈的跟踪信息 - 告诉你发生了什么。堆栈跟踪可以是很大的,特别是当你使用C++STL时。要从下往上读才是用帮助的。如果堆栈跟踪不是足够大,可以使用--num-callers选项使它变得更大。

--num-callers=

  • 代码地址(比如,0x108668)通常来说是不重要的,但偶尔对于追踪怪诞的问题是至关重要的。
  • 一些错误信息会有第二个组件,用来描述包含的内存地址。这里表明要写的内存刚好超过了在a.c第6行malloc()分配的heap单元的边界。

由于之后的错误可能是由于之前的错误导致的,所以应该按照报告的顺序修改错误。而如果不这样做往往是觉得Memcheck难用的原因。

内存泄漏看上去这样的:

==12402== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1

==12402== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==12402== by 0x10865B: f (a.c:6)

==12402== by 0x108679: main (a.c:13)

堆栈跟踪告诉我们泄漏的内存是哪里分配的。不幸的是,Memcheck并不能告诉你为什么内存泄漏。

有好几种内存泄漏的类型,其中两种是最重要的:

  • "difinitely lost":你的程序正在泄漏内存 - 修复它
  • "probably lost":您的程序正在泄漏内存,除非您使用指针做一些有趣的事情(例如将它们移动到指向堆块中间的位置)。

Memcheck也会报告一些未初始化值的使用情况,最常见的消息是"Conditional jump or move depend on uninitialised value(s)"。这样的错误是很难找到root causes的。可以尝试使用

--track-origins=yes

来获得额外的信息。这会让Memcheck运行的更慢,但这些额外的信息会使得节省更多的时间来找出这些未初始化值到底是从哪里来的。

注意事项

Memcheck并不是完美的,偶尔会产生误报,并且有一些机制可以抑制这些误报。然而,一般99%是正确的,所以你应该提防自己忽视这些信息。毕竟,你不会忽视编译器的警告信息,不是吗?如果Memcheck报告了一些你不能修改的库中的代码错误,抑制机制也是有用的。默认的抵制机制是把这些都隐藏掉,但你可能会遇到这多的这种情况。

Memcheck不能侦测到你的程序中每一个内存错误。比方说,它不能侦测到对静态分配或在栈上的数组进行的超范围的读和写。但它可以侦测到许多让你程序crash的错误(比方说造成一个segmentation faultu段错误)。

尝试让你的程序变得干净,这样Memcheck就不会报告错误信息了。一旦你达成了这个目标,那么当改变程序造成Memcheck报告新的错误时,就会变得更加容易观察。从好几年对Memcheck的使用经历来看,让庞大的程序在运行Memcheck后,变得cleano都是有可能的。比方说:大部分的KDE,OpenOffice.org以及Firefox都是Memcheck-clean或相当接近的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值