2012-02-22 65 views
1

這裏有沒有內存泄漏?爲什麼會立即銷燬共享指針泄漏內存?

class myclass : public boost::enable_shared_from_this<myclass>{ 
//... 
    void broadcast(const char *buf){ 
    broadcast(new std::string(buf)); 
    } 

    void broadcast(std::string *buf){ 
    boost::shared_ptr<std::string> msg(buf); 
    } 
//... 
}; 

(這是精簡版仍然顯示問題 - 通常我做實事在第二broadcast的來電!) 我的假設是,在第一次調用得到了一些記憶,然後因爲我做什麼用第二次調用的智能指針會立即刪除它。簡單?但是,當我運行我的程序時,內存會隨着時間的推移而增加,跳躍。然而,當我在節目中唯一打電話給廣播()時,它不會!

ps的輸出爲版本,而不broadcast()

%CPU %MEM  VSZ RSS TIME 
3.2 0.0  158068 1988 0:00 
3.3 0.0  158068 1988 0:25 (12 mins later) 

隨着呼叫向broadcast()(在Ubuntu 10.04,克++ 4.4,助推1.40)

%CPU %MEM  VSZ RSS TIME 
1.0 0.0 158068 1980 0:00 
3.3 0.0 158068 1988 0:04 (2 mins) 
3.4 0.0 223604 1996 0:06 (3.5 mins) 
3.3 0.0 223604 2000 0:09 
3.1 0.0 223604 2000 2:21 (82 mins) 
3.1 0.0 223604 2000 3:50 (120 mins) 

(眼看跳躍在約3分鐘可以在我已經嘗試過的幾次重現)

隨着broadcast()(Centos 5.6,g ++ 4.1,boost 1.41)的調用

%CPU %MEM  VSZ RSS TIME 
0.0 0.0  51224 1744 0:00 
0.0 0.0  51224 1744 0:00 (30s) 
1.1 0.0 182296 1776 0:02 (3.5 mins) 
0.7 0.0 182296 1776 0:03 
0.7 0.0 182296 1776 0:09 (20 mins) 
0.7 0.0 247832 1788 0:14 (34 mins) 
0.7 0.0 247832 1788 0:17 
0.7 0.0 247832 1788 0:24 (55 mins) 
0.7 0.0 247832 1788 0:36 (71 mins) 

這裏是正在爲如何broadcast()調用(從一個boost :: ASIO定時器),現在我想知道它是否能發揮作用:

void callback(){ 
//... 
timer.expires_from_now(boost::posix_time::milliseconds(20)); 
//... 
char buf[512]; 
sprintf(buf,"..."); 
broadcast(buf); 
timer.async_wait(boost::bind(&myclass::callback, shared_from_this())); 
//... 
} 

(回調是在同一類的廣播功能)

我有4個這樣的定時器,我的io_service.run()被3個線程池調用。我的20ms超時意味着每個計時器都會以50次/秒的速度調用broadcast()。我在我的函數開始時設置了到期時間,並在接近結束時運行計時器。被遺忘的代碼並沒有那麼做;將調試信息輸出到std :: cout可能是佔用CPU最多的工作。我想有時可能會立即觸發計時器;但是,我仍然不明白這會是一個問題,更不用說造成內存泄漏。

(該程序運行正常,順便說一下,做了充分的任務即使;我只當我發現通過PS報告的內存使用量已經跳起來了疑惑。)

UPDATE:感謝答案和評論。我可以補充說,我將​​程序在每個系統上運行了幾個小時,內存使用量沒有再增加。 (當Centos版本第二次跳轉時,我也準備將其視爲一次性堆重組或其他東西)。無論如何,很高興知道我對智能指針的理解仍然健全,並且存在沒有我需要關心的線程的奇怪的角落案例。

+4

1)您的代碼示例不能編譯。 2)在我[修復](http://ideone.com/FCPHf)之後,我將它運行在valgrind下。它不會泄漏。 – 2012-02-22 06:49:43

+1

我懷疑你正在看到堆管理的效果,而不是泄漏(例如碎片等)。有時候堆管理器可能會給你一個新的內存塊,而不是重複使用現有的內存管理器來考慮性能,而且這種行爲是不確定的。如果你想真正檢查這些東西,請使用調試分配器(MSVC++隨附一個,對於GCC,你可以像Rob那樣使用Valgrind) – 2012-02-22 07:06:39

+0

如果你顯示的代碼是程序唯一的東西,它可能是一個問題。但是,您可能也在做其他許多事情,並且可以輕鬆解釋其中的差異。 – 2012-02-22 07:09:43

回答

2

如果有泄漏的消息,則分配一個std::string(20字節,更多或更少的)50倍每秒。 在1小時內您應該已經分配... 3600 * 50 * 20 = 3,4MBytes。

您看到的與64K無關,這可能是由於系統將內存分配給進程的方式,即new子分配給變量。

系統在刪除某些內容時需要「垃圾回收」,將其重新放回可用內存鏈以供進一步分配。 但是,由於這需要時間,所以大部分系統都不會執行此操作,直到釋放的內存超過了一定的數量,這樣才能完成「重新打包」。

1

那麼,這裏發生的事情可能不是你的程序正在泄漏,但由於某種原因,系統內存分配器決定爲你的應用程序保留另一個64 kB頁面。如果在這一點上存在一個持續的內存泄漏,那麼在50 Hz的速率下,這將會產生更爲戲劇化的效果!我不知道(我不是那個領域的專家),但我猜想有一些啓發式和統計數據涉及到了。我不知道(我不是這方面的專家)。或者,它可能僅僅是堆已經分散。

可能發生的另一件事是,你是保持在緩衝器變長隨時間:)