2012-04-02 76 views
4

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

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

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

+0

您的代码可能不会以传统意义上泄漏内存,但是这些类型的资源问题偶尔会出现,即使您知道代码进出,通常也很难找到。没有看到你的代码,就不可能知道发生了什么。 – Chad 2012-04-02 18:58:31

+2

在这种情况下,Valgrind的工具Massif可能比缺省工具Memcheck更有用。 – ninjalj 2012-04-02 19:00:24

回答

4

Valgrind只能检测到或多或少没有被删除的指针。当你不需要它们时保持它们是另一个问题。

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

如果你正在捕捉所有的例外(...)并且没有对它们做任何事情,那么不要这样做。这是一个常见原因。其次,在关机期间调用的析构函数的日志文件可能会有所帮助。也许在main()结束时,设置一个全局标志;在设置该标志时调用的任何析构函数都可以输出它们存在的结果。看看是否有很多对象不应该在那里。

稍微简单一点,你可以使用一个全局变量,每个ctor可以递增1,而dtor递减1.如果你发现对象的数量不是相对保持不变,你可以调查哪些正在使用类似的技术来解决问题。

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

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

不幸的是,这个问题会变得很糟糕,因为在持久的地方分配了小对象。例如,可能有50字节的类在内存中分开300kb,并且像其中的100字节一样,但是在该空间中不能分配512kb的对象,因此它为每个新对象分配了额外的512kb,有效地浪费了90%免费“空间,即使你的程序已经拥有足够多的空间。

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

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

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

如果不再需要,您可能需要检查代码和空闲内存。

3

尝试使用Valgrind Massif工具。从Massif manual

另外,还有一些不是由 传统泄漏跳棋,如MEMCHECK的检测一定的空间泄漏。这是因为 内存实际上并没有丢失 - 指针保持不变 - 但它的 未被使用。像这样泄漏的程序可能会不必要地增加它们随着时间的推移使用的内存量。 Massif可以帮助识别这些泄漏。

地块应该告诉你发生了什么,记忆和它被分配的位置,直到关机时才释放。