2009-11-24 51 views
4

我正在尋找託管/非託管API,這將允許我查找哪些對象引用另一個對象,並有可能使其不被垃圾收集。獲取對象的活動引用

這樣的API可能是這樣的:

var foo = new Foo(); 
var bar = new Bar(); 
bar.Foo = foo; 

var references = GC.GetReferencesTo(foo); 
// references is an array that contains bar 

我知道廓線儀,可用於這一點,但我想使它成爲一個單元測試的一部分。是否有可以使用的託管或非託管API?

+1

看到這個相關的問題:http://stackoverflow.com/questions/1786083/how-do-i-iterate-through-instances-of-a-class-in-c/1786354#1786354 – 2009-11-24 00:29:55

回答

5

非託管dll SOS(Son of Strike)提供了一種實現此目的的方法,雖然我不相信它具有明顯的腳本支持,也沒有提供通過單個命令實現此目的的簡單方法。你將不得不反思變量的地址,檢查變量的所有gcroots(顯然會包括堆棧)並處理其餘部分。我會建議,如果你想證明一個對象是而不是引用,一個更簡單的技術將(暫時)使其可以finalizeable,確保它不再引用你的單元測試堆棧和然後通過GC.Collect()強制多個垃圾收集,然後使用GC.WaitForPendingFinalizers()

你的finalize方法可以設置一個靜態布爾標誌,然後你的單元測試可以斷言這是真的。

我會質疑實用程序沒有進一步的解釋,但這可能是證明在單元測試中不存在懸掛參考的最簡單方法。

+0

我目前使用WeakReference對象後面跟着一個GC.Collect/WFPF,然後聲明引用爲空來告訴我它是否已被清除。我將其作爲單元測試的一部分來確保我的API不會導致泄漏。但作爲'assert'輸出的一部分,我想打印出哪些對象保持活動狀態,以便讓我跳進剖析器。 – 2009-11-24 00:23:30

+0

我認真地懷疑,如果沒有大量的工作來自動公開SOS功能,那麼這是可能的自動方式,除非MS內的人已經這樣做了。我建議最好的辦法是考慮編寫基於SOS的東西,將整個搜索自動化到一個命令中,以便在調試器中從失敗的測試中觸發它。請注意,SOS不是一個獨立的工具,它完全依賴於一個兼容的調試器被連接... – ShuggyCoUk 2009-11-24 00:44:14

+1

如果你真的想嘗試破解它在這裏的一個凝視點:http://blogs.microsoft.co.il/ blogs/sasha/archive/2009/08/17/gc-helper-for-obtain-live-instances-of-a-type-or-how-i-implemented-gc-getaliveinstancesof-lt-t-gt.aspx – ShuggyCoUk 2009-11-24 00:47:43

1

還記得.NET使用traced garbage collection所以其他對象引用的對象 - 例如對象圖 - 如果您的應用程序不再引用任何對象,GC仍會清除它;它比經典的引用計數垃圾收集算法pre-.NET更聰明。這意味着,即使您找到一種方法來查明對象的所有引用,其中一些引用可能並不重要,也可能不需要照顧。

這並不直接回答如何找到一個對象的所有引用,但確實讓讀者瞭解的情況是,當你發現通過工具或實用程序的所有引用,某些種類的事情不需要在.NET中被修復 - 例如經典的循環引用,因此在嘗試修復內存泄漏時,您可能不得不尋找一些巧妙的方法來知道要忽略什麼。

此解釋僅適用於託管代碼方案。

3

.NET探查使用profiling API跟蹤對象的曲線圖。你可能特別感興趣的回調方法ObjectReferencesRootReferences,也可能是ObjectAllocated。前兩種方法將在每次垃圾回收後被調用來覆蓋整個活動對象圖,因此單獨攔截它們就足以重建該圖,然後以任何您想要的方式對其進行分析。

This article介紹瞭如何把所有的拼在一起。

+2

文章從該鏈接丟失 – TankorSmash 2015-11-13 01:32:51