2012-04-02 73 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可以幫助識別這些泄漏。

地塊應該告訴你發生了什麼,記憶和它被分配的位置,直到關機時才釋放。