找到大量分配的内存

时间:2012-04-02 18:40:12

标签: c++ c memory valgrind

我有一个用c / c ++编写的程序(守护进程)。它运行完美,但经过一段时间(可能是5天,一周,2周)后,就会分配大量的兆字节内存。我无法理解代码的哪些部分没有释放分配的内存。在启动时,内存使用量约为20-30兆字节。然后在一段时间之后,或者可能是事件,它以每小时1Mb的速度缓慢增长,如果没有终止,则会因为没有可用内存而崩溃。

我已经尝试使用Valgrind,并且当它已经分配了大约500Mb的内存时,以通常的方式关闭了该守护进程。关机过程真的很长,但是当它完成时Valgrind表示没有发现内存泄漏,除了mysql_init / mysql_close程序(大约504字节肯定会丢失)。谷歌表示不要担心这个Mysql漏洞,并提供一些原因,为什么像Valgrind这样的内存诊断工具认为它是泄漏。

我真的不知道代码的哪些部分会分配内存但只在程序关闭时释放它。帮我看看这个

3 个答案:

答案 0 :(得分:4)

Valgrind只检测或多或少删除未删除的指针。当你不需要它们时保持它们是一个不同的问题。

首先,关闭时释放所有对象和内存。如果有泄漏,valgrind会将其检测为未被对象引用的内存等。然而,操作系统最终会释放任何泄漏。

如果您正在捕捉所有异常(...)并且没有对它们做任何事情,那么,不要这样做。这是一个共同的原因。

其次,在关闭期间调用的析构函数的日志文件可能会有所帮助。也许在main()的末尾,设置一个全局标志;设置该标志时调用的任何析构函数都可以输出它们存在。看看是否有很多对象不应该存在。

稍微容易一点,你可以使用一个全局变量,每个ctor可以将它递增1,并且dtor递减1.如果你发现对象的数量没有保持相对相同,你可以调查哪些是使用类似技术解决问题。

第三,使用Boost及其范围的智能指针来帮助,但不要依赖智能指针作为圣杯。

我遇到了一个潜在的问题。对于长时间运行的程序,内存碎片会导致大量内存使用。您可以删除1mb对象,然后尝试创建一个2mb对象;创造将在新的空间,因为1mb'免费块'不够大。然后,当你创建一个512kb的对象时,它可以进入那个1mb对象的空间,只使用1/2的可用空间,但要使你的下一个1mb对象需要在大空间中分配。

不幸的是,由于在持久性场所分配了小对象,这个问题会变得很糟糕。例如,在内存中可能存在相隔300kb的50字节类,并且像其中的100个,但是在该空间中不能分配512kb对象,因此它为每个新对象分配额外的512kb,实际上浪费了90%的实际值。即使您的程序已经拥有足够的空间,也可以免费使用空间。

这个问题很难被追查为明确的原因,但是如果你检查一下程序的流程,那就寻找小的分配。记住std :: list / vector / etc.都可以造成这种情况;如果你想制作一个可以运行大量内存运行数周的守护进程,那么使用reserve()预先分配内存是个好主意。内存池甚至更好。

根据您要放入的时间,您还可以创建(或查找)自定义内存分配器,该分配器也会在关闭时报告对象。

答案 1 :(得分:3)

尝试使用Valgrind Massif工具。来自Massif manual

  

此外,还有一些空间泄漏未被检测到   传统的泄密检查器,如Memcheck的。那是因为   记忆力实际上并没有丢失 - 指针仍然存在 - 但它确实存在   没用像这样泄漏的程序可能会不必要地发生   随着时间的推移增加他们使用的内存量。地块可以   帮助识别这些泄漏。

Massif应该向您展示内存发生了什么以及分配的位置,并且在关闭之前不会释放。

答案 2 :(得分:1)

由于您确定没有内存泄漏,您的程序可能会分配内存并存储数据而不会泄漏。

例如,假设您的程序使用链接列表...

struct list{
DATA_ARRAY arr; //Some data 
struct *list next;
};

While(true) //infinite loop
{
// Add new nodes to list 
// Store some data in the node
}

这里没有泄漏。但是循环会永久地添加新节点并存储数据,一切都非常有效。但是内存使用量一直在增加。由于你运行2-5天,这样的事情当然是可能的。

如果不再需要,您可能需要检查代码并释放内存。

相关问题