[英].NET GC deleting object in use
我遇到了一個問題,在該問題中似乎GC線程正在喚醒並在使用對象時將其刪除。
當processfoo運行時,在返回之前,它會在單獨的線程中觸發fooCopy析構函數。 有人看到過這樣的問題嗎?如果是,您如何解決呢? 當然,這不可能真的發生,我必須做錯了什么。 誰能給我一些調試垃圾收集的提示/策略?
try
{
CFoo fooCopy = new CFoo(someFoo);
someBar.ProcessFoo(fooCopy);
}
CFoo具有IntPtr成員變量。 ProcessFoo將該成員變量從C ++ DLL傳遞到導入的函數,這可能需要花費幾秒鍾來運行。
在我的C ++ DLL中,我記錄了何時創建IntPtr以及何時刪除了IntPtr,並且可以看到在ProcessFoo運行時刪除IntPtr的單獨線程。
當然,這不可能真的發生,我必須做錯了什么。
是的,這絕對是有可能發生的(這就是為什么編寫終結器很難,並且您應該盡可能避免使用終結器,並且在強制編寫終結器時要非常小心)。 只要運行時證明沒有代碼會再次嘗試訪問該對象,就可以對其進行GC處理。 如果你調用一個實例方法(和任何時間調用之后從未訪問對象實例),那么物體的最近使用后立即可享有集合this
從實例方法。
在范圍內(例如,方法的this
變量)但在該范圍內不再使用的對象不會被GC視為根對象 。
至於如何解決它,如果您擁有一個即使不再在托管代碼中都無法訪問的變量,都希望將其視為“有效”的變量,請使用GC.KeepAlive
。 在這種情況下,將GC.KeepAlive(this)
添加到ProcessFoo
的末尾將確保所討論的對象保持活動狀態直到方法結束(或者,如果不是該方法的職責,請調用方調用GC.KeepAlive(someBar)
就在ProcessFoo
之后)。
當您與C ++互操作時,這是很正常的,GC沒有希望發現IntPtr在其他任何地方都在使用。 這不是GC知道的參考類型,也不能探測本機代碼的堆棧框架。 抖動fooCopy
對象引用標記為fooCopy
使用到基礎CALL,而不超出此范圍。 換句話說,它可以在執行本機代碼時進行收集。 如果另一個線程觸發了GC,則為sayonora。
您可以在這篇文章中找到有關局部變量生存期的詳細信息。
有幾種可能的解決方法,盡管無法從問題中猜出正確的方法。 除了SafeHandle類之外,還非常擅長確保完成終結處理,可以在[DllImport]聲明中使用HandleRef
代替IntPtr。 或將GC.KeepAlive()
附加到此代碼,以強制抖動延長fooCopy的壽命。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.