2010-08-03 48 views
1

注意:這可能聽起來很愚蠢。 我有一個應用程序使用原始指針,並且應用程序中存在大量內存泄漏。用智能指針替換現有的原始指針

現在我的問題是,用智能指針替換現有的原始指針是多麼容易。 而只是替換它們的幫助是減少由於未釋放動態分配的內存而導致的內存泄漏。

爲了進一步解釋,這個應用程序是一個傳統應用程序,並且存在非常直接的內存泄漏,其中內存將被分配並且不會在相同的函數本身中被釋放。

我使用DevPartner完成了一次內存分析,發現了很多區域。 Valgrind是否比Devpartner更好?

回答

3

使用智能指針當然是清理應用程序的好開始,但它們不是萬能的。大量的內存泄漏可能是設計良好的程序中的粗心大意,但更有可能出現重大的設計問題,而內存泄漏就是其中的一個症狀。當你切換到智能指針時,你仍然需要做出諸如「誰擁有這個對象」,「這個對象在多個客戶端之間共享的所有權」和「這個對象的預期生存期是什麼」等設計選擇以便選擇針對特定場景的適當的智能指針實現。但是,這將是一個很好的開始,因爲在不同情況下選擇適當的智能指針的過程會迫使您考慮這些事情,並可能會改進您的設計。

1

這取決於,如果對對象的硬引用阻止垃圾收集器釋放垃圾回收程序,垃圾收集程序仍然可能存在內存泄漏。如果你想知道內存泄漏發生在哪裏,可以使用一個分析器或寫單元測試和模擬對象。

編輯:爲了獲得智能指針的好處,您還必須掛鉤或實現自己的垃圾回收器,因爲它不是語言功能。

編輯2:智能指針顯然實現引用計數,這是一個垃圾收集策略。

+1

智能指針與垃圾收集不同。 – 2010-08-03 13:46:21

+0

啊,好點。注意:-) – gtrak 2010-08-03 13:58:14

+1

只要你的模型沒有循環,你就不需要任何帶有智能指針的垃圾回收器。你只需要用普通的指針來打破這個循環。我用了多年的智能指針,從來沒有實現gc也沒有任何內存泄漏 – mb14 2010-08-03 13:59:58

2

毫無疑問,智能指針可以減輕程序員內存所有權麻煩的負擔。既然你沒有提到這是一個遺留應用程序還是它改變接口有多容易(因爲智能指針會降級到原始指針,所以並不總是需要),我建議你使用valgrind之類的工具來運行你的應用程序(在Linux上)或純化(在Unices和Windows上)來跟蹤內存泄漏。

根據我的經驗,大多數內存泄漏遵循某種模式(開發人員A錯過了一些東西,開發人員B複製了該代碼並且伴隨着問題)。因此,在考慮使用智能指針之前,使用工具可能會首先解決內存泄漏問題。

如果您正在開發此應用程序 - 從使用智能指針開始。他們將爲您節省大量的時間和精力。

0

智能指針'代碼'擁有對象中的文檔。所以對於每一個指針,你必須將'在一些程序員頭部的模糊文檔'轉換成'精確的代碼文檔'。大多數選擇都很簡單。這仍然留下了很多不是的選擇。除了所有權以外,您還必須擔心使用弱指針來破壞對象圖循環。因此,這種整體轉換爲智能指針並不是一項簡單的任務,如果循環中斷部分錯誤,您甚至會引入新的內存泄漏。

+0

智能指針文檔的唯一內容是:「我不在乎誰擁有這個對象,只是確保在最後正確銷燬它」。你不知道誰引用了這個對象,你也不知道最後一個引用何時會超出範圍,所以你不知道對象何時會被銷燬。總而言之,你不知道對象的生命週期,因爲沒有一個所有者。每個人都擁有這個對象(因爲每個客戶都可以銷燬它),所以沒人擁有這個對象。所以「所有權」根本沒有記錄。 – 2010-08-03 14:50:29

+0

我認爲你把'所有權'和'只有一個對象所有權'等同起來會有點困惑。大多數代碼涉及(明示或暗示)共享所有權。當你說(因爲每個客戶都可以銷燬它),用智能指針沒有人可以銷燬它,只需釋放所有權。 – jyoung 2010-08-03 14:59:58

+0

@Frerich你似乎指的是一種特定類型的智能指針,一種引用計數的指針,但是對於不同的所有權場景,有不同類型的智能指針。請參閱http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/smart_ptr.htm。如果智能指針的風格在特定情況下被選擇得很好,那麼它就是在代碼中記錄對象所有權策略的絕佳方式。 – bshields 2010-08-04 13:57:50

2

我打算給這個「非常可能」的公司。

內存泄漏的一種形式是當函數分配內存並且至少在函數外的一個路徑中不刪除它。某種範圍的指針,如auto_ptr,可能處理得很好。 (注意:auto_ptr是第一個ISO標準的一部分,並且在下一個標準中將被棄用,所以很難給出關於使用什麼範圍指針的建議。請參考您的編譯器和庫文檔以查看它們支持的內容。)

另一種形式是對象被分配的位置,所有權是共享的,這意味着有多個例程使用它,並且沒有簡單的方法來判斷每個人是否都在使用它。這是shared_ptr的一個很好的候選人,但你必須謹慎使用。創建對象時分配給shared_ptr,並確保每個其他指針的使用都是shared_ptr。如果例程A,B和C通過shared_ptr訪問對象,並且您沒有更改D,那麼當例程A,B和C完成時,它將消失,無論D的需要如何。要避免與shared_ptr

一件事是循環的,因爲如果我有一個shared_ptr至J,J具有shared_ptr到K,且K具有shared_ptr給我,這些都不是以往任何時候都將被刪除,即使如果在程序中的其他地方無法訪問。你需要注意這些情況。你可以在循環中用weak_ptr分解它們,或者刪除循環中的某個元素,或者只是處理泄漏。

要考慮的另一件事是用vector和類似的容器替代動態分配的數組和其他動態分配的數據結構。這給你免費的大量內存管理,儘管你仍然可以泄漏內存。如果一個矢量變大,然後變小,它不會釋放額外的內存。通常的做法,如果你確實需要回收記憶,那麼就是swap帶有自身副本的一次大的向量。

簡而言之,有很多非常有用的工具可以自動執行大量的內存管理,但它們不會替代您的想法。只需將每個指針變爲shared_ptr並將每個數組變成vector即可解決很多問題,但智能地使用這些指標會帶來更大的好處。