查找巨大的已分配内存块



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

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

我真的不知道代码的哪些部分分配内存,但只有在程序关闭时才能释放内存。帮助我查找此

Valgrind只检测或多或少未删除的指针。当你不需要它们的时候,把它们留在身边是另一个问题。

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

如果你发现了所有的异常(…),却没有对它们采取任何措施,那么,不要这样做。这是一个共同的原因。

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

更简单的是,您可以使用一个全局变量,每个ctor可以将其递增1,dtor递减1。如果你发现对象的数量没有保持相对不变,你可以使用类似的技术来调查哪些对象造成了问题。

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

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

不幸的是,由于小对象被分配在持久的位置,这个问题可能会变得很糟糕。比如说,内存中可能有50个字节的类,它们相距300kb,就像100个一样,但在这个空间中不能分配512kb的对象,所以它为每个新对象分配额外的512kb,这实际上浪费了90%的实际"可用"空间,即使你的程序已经拥有了足够的空间。

这个问题很难找到确切的原因,但如果您检查程序的流程,请寻找小的分配。记住std::list/vvector/等。都会导致这种情况;如果您想让一个执行大量内存操作的守护进程运行数周,那么最好使用reserve()预分配内存。内存池甚至更好。

根据您想要投入的时间,您也可以制作(或找到)一个自定义内存分配器,它也会在关闭时报告对象。

尝试使用Valgrind Massif工具。来自Massif手册:

此外,某些空间泄漏未被传统的泄漏检测程序,如Memcheck。这是因为内存实际上从来没有丢失过——指针仍然指向它——但它未使用。有这种泄漏的程序可能不必要随着时间的推移,增加他们正在使用的内存量。Massif can帮助识别这些泄漏。

Massif应该向您展示内存发生了什么,以及内存在哪里被分配,直到关闭才释放。

既然您确信没有内存泄漏,那么您的程序可能正在分配内存并存储数据而不会泄漏。

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

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天,这样的事情肯定是可能的。

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

最新更新