2009-07-06 43 views
9

我在混合模式C++/CLR .NET應用程序中遇到內存泄漏緩慢的問題。混合模式C++/CLR應用程序中的內存泄漏

(鏈接到VS2008 C++/CLR的Windows窗體應用程序與 「/ CLR」 編譯器設置它的C++原生靜態庫)

典型行爲:應用程序開始使用30 MB(專用內存)。然後泄漏內存速度緩慢,例如在模擬重負載下運行時每小時一個MB。這模擬了應用程序在幾天或幾周內正在運行。

我一直在使用一些工具來跟蹤內存泄漏既包括隨Visual Studio的CRT庫的CRT調試的東西嘗試。我還使用了商業泄漏檢測工具(「Memory Validator」)。

兩個報告在關機時可忽略不計的內存泄漏(我不是擔心一些小的條目數量到幾KB)。另外,我可以看到在運行時,跟蹤的內存看起來不那麼重要(所以我不相信這只是內存,只在應用程序退出時釋放)。我獲得了大約5 MB的上市內存(總數> 30MB)。

所述的工具(存儲器驗證器)是設置跟蹤所有的內存使用情況(包括malloc的,新的,虛擬存儲器分配和一大堆其它類型的存儲器分配的)。基本上,每個設置的內存來跟蹤已被選中。

在.NET圖像報告它周圍使用1.5 MB的存儲器(從性能監視器)。

這裏是信息的最後一點:我們有一個版本,它運行作爲本地控制檯應用程序應用程序的(純天然 - 不CLR在所有)。除了沒有UI的東西外,這與混合模式的95%相同。這似乎並沒有泄漏內存,並在專用字節大約5MB處出現峯值。

所以基本上我試圖讓人們在這裏要說的是,我不認爲任何本地代碼的泄漏內存。

另一塊拼圖:我發現這個目標2.0框架(對此我),當是指內存泄漏在混合模式下的應用:http://support.microsoft.com/kb/961870

不幸的是,細節僵硬稀疏,所以我不知道這是相關的。我確實嘗試了針對3.5框架而不是2.0,但仍然有同樣的問題(也許我沒有這樣做)。

任何人有任何建議嗎?

幾件事情,可能會幫助我:

  • 是否有任何其他種類的,我不是跟蹤內存分配的?
  • 這些數字如何不加起來?我獲得了5 MB的CRT內存使用量,1.5 MB的.NET內存,那麼整個應用程序如何使用30 MB專用字節?這一切都綁在.NET框架?爲什麼我沒有看到這些泄漏工具? .NET框架不會顯示爲某種分配的內存嗎?
  • 任何其他泄漏檢測工具,適用於混合模式應用程序?

感謝所有幫助

約翰

+0

.NET 2.0和.NET 3.5都使用相同的CLR 2.0,因爲您可以從版本號輕鬆看到;-) – 2009-07-16 07:29:20

回答

6

好的,我終於找到了問題。

這是由於/ EH(異常處理)的設置不正確引起的。

基本上,使用混合模式的.NET應用程序,您需要確保所有靜態鏈接的庫都使用/ EHa而不是默認/ EH進行編譯。

(軟件本身還必須與/ EHA編譯,但是這是一個給定的 - 編譯器,如果你不使用它會報告錯誤的問題是,當你在其他靜態本地庫鏈接。)

問題是,使用/ EHs編譯的本機庫中引發的應用程序管理位中捕獲的異常最終無法正確處理異常。然後C++對象的析構函數不能正確調用。

在我的情況下,這隻發生在一個罕見的地方,因此爲什麼花了我很多時間來發現。

0

試用:DebugDiags
生成一些內存轉儲後,它會給你一個很好的內存分配的總結,並且根據找到你的PDB,它可以告訴你它被分配的人。

+0

謝謝我會試試 – John 2009-07-09 10:18:07

0

您可能有參考泄漏,請查看ANTS分析軟件。 Ants Profiler

引用泄漏是內存泄漏的.net等價物,您持有對對象的引用,從而阻止它被垃圾收集,因此您使用的內存開始增加。

+0

但是不會在「##所有堆中的字節「.NET內存值? 我一直在Process Explorer中看到它,它不會泄漏。 泄漏是私有字節,但不是「所有堆中的#字節」。 – John 2009-07-09 10:17:31

0

是否有可能您錯過了一些垃圾處理器,如果您使用GDI +和其他許多API,可能會發生這種情況。

如果您運行靜態分析工具FXCop,它有一個規則來檢查您是否在提供接口的對象上調用了dispose(或使用「using」)語句。在.Net中,如果函數使用非託管代碼,它通常會爲您提供一種處理或關閉方法,以避免泄漏資源/內存。

+0

好主意。我猜這些泄漏不會顯示爲CLR內存使用,因爲它們是本地的,但也不會出現在本機泄漏檢測工具中,因爲它們不是我的代碼。 我會給一個bash(我不知道FXCop是否可以處理混合模式的C++/CLI) – John 2009-07-16 10:17:33

+0

希望它有幫助。我只是在黑暗中拍攝,但我發現在使用GDI的應用程序中發生了這種情況,我發現幾乎GDI +中的每個對象都需要一個處理器。請注意,這是「使用」 – Spence 2009-07-16 12:09:47

4

像斯賓塞說的,但對於C++/CLI)....

對於任何對象,您使用的是C++/CLI中,如果你創建更多的對象,從你的C++代碼,你應該嘗試使用堆棧分配語法,儘管這是一種編譯器的神奇事物,但它可以設置嵌套的__try {} __finally {}語句,您可能習慣使用本地代碼(這是以某種方式設置它們的方式)放棄對Dispose的調用)。

Nish'sarticle at the code project here關於C++/CLI堆棧分配語義非常好,深入探討了如何使用{}進行模擬。

你也應該確保刪除任何對象是implment IDisposable的,因爲你不能調用Dispose在C++/CLI,刪除這是否適合你,如果你不使用棧語義..

我通常所說的關閉自己在Streams上,並在完成對象的時候嘗試分配nullptr,以防萬一。

您可能還需要檢查出this article on memory issues,perticularly有關事件的用戶,如果您分配事件對你的對象,你可能會被泄露......

作爲最後的手段(或者先:),一個我曾經做過的事情是利用CLR profiler API,here's another article就如何做到這一點,作者的作者(傑伊Hilyard)有一個例子,答案;

  • 使用的每個.NET類型,如何 許多對象實例被分配 ?
  • 每種類型的實例 有多大?
  • 什麼通知 GC提供,因爲它通過垃圾回收去 什麼 你可以找到?
  • GC 何時收集對象實例?

應該讓你比一些商品探查一個更好的主意,我注意到,他們可以偶爾會誤導取決於你的配置porofile(順便說一句,注意大對象堆的問題,>〜83KB的對象會被特殊處理,在這種情況下,我會推薦,離開大堆物體:)。

考慮您的意見,一些事情......

我有關圖像負載不是計費配額或其他任何disernable統計之前已經發布,這是什麼意思,你可能需要跟蹤一些手柄或裝載機問題(最終會看到loader loader),但在此之前,你可以嘗試設置一些Constrained Execution Regions,它們可以創造奇蹟,但不幸的是很難修改爲非純代碼。

這最近MSDN Mag,文章文件的許多perfmon類型的內存sperlunking(後續this older one)。

來自VS Perf Blog,他們展示瞭如何在Visual Studio中使用SOS,它可以方便地追蹤胭脂DLL的相關帖子也很好。

Maoni Stephen's Blog and company,他說他是在perf隊,但他的職位基本上100%都是關於GC的,所以他可能寫得很好。

Rick Byers是一位擁有CLR診斷團隊的開發者,他的許多博客夥伴也是不錯的消息來源,但是,我強烈建議也提及相當新的dev/diagnostics forum。他們最近擴大了他們的討論範圍。

Code Coverage Toolstracing通常可以提供幫助,讓您瞭解實際運行的內容。 (具體來說,那些相關的統計數據可能不會給你一個關於什麼是你的代碼的全局視圖,我可以說最近我發現(即使使用.net4beta二進制文件,this company的分析器也是相當不錯的,它能夠從它的配置文件軌跡中導出本機/管理泄漏,將您帶回到確切的源代碼行(即使經過優化,相當不錯(並且它有30天的試用版))))。

祝你好運!希望這對我有幫助,因爲我現在正在做很多相同的工作;)