我在尋找管理思想在.NET程序集,然後被傳遞迴非託管代碼創建的COM對象的生存期。對Marshal.ReleaseComObject和返回值
背景: 我們的軟件引擎被編碼在非託管C++。我們的軟件的功能可以使用引擎的COM對象組件進行擴展。多數情況下,發動機本身並不需要改變多年。但是,我們繼續構建更多組件來爲我們的軟件添加新功能。雖然這些組件過去也是使用非託管C++構建的,但在過去的幾年中,我們一直在用C#編寫這些插件。
直到最近,我們已經訂閱了這個想法Marshal.ReleaseComObject不應該在C#組件中使用的非託管COM對象上調用,而是允許RCW和垃圾收集管理它們的生命週期。
這個理論聽起來不錯,但實際上我們已經開始在我們的軟件中遇到內存問題,這似乎是GC懶惰地清理這些COM對象造成的,在某些情況下,我們的軟件會用盡所有可用的記憶和失敗。
有一些錯誤,我們可能會犯被阻止GC和RCW作用於這個對象?垃圾收集的想法不是它會做什麼必要的,以確保內存在需要時是免費的?
由於缺乏更好的想法,我們不情願地開始利用Marshal.ReleaseComObject的(以及在某些情況下FinalReleaseComObject)。一般來說,這看起來確實有用。
然而,在試圖開發使用Marshal.ReleaseComObject的一個統一的模式,我們發現在我們不知道它是可以使用它一個案例。某些組件需要將COM對象返回值傳遞迴非託管引擎。組件再也不會再看到返回值,並且(當前)無法在不再使用時收到通知。例如:
// Unmanaged C++ code
Engine::Engine() : m_ipDoodadCreator(CLSID_FancyComponent)
{
}
void Engine::ProcessDoodad()
{
try
{
// Smart pointer
IDoodadPtr ipDoodad = m_ipDoodadCreator->CreateDoodad();
...
ipDoodad = NULL; // Calls Release...
}
catch (...) { ... }
// At this point the doodad lives on because the RCW is holding a
// reference to it.
}
// Managed C# Component
public class FancyComponent : IDoodadCreator
{
public IDoodad IDoodadCreator.CreateDoodad()
{
// IDoodad is implmented in unmanaged c++
IDoodad doodad = new IDoodad();
try
{
...
return doodad;
}
finally
{
// Can't do this here because engine doesn't yet have
// a reference to doodad.
// Marshal.ReleaseComObject(doodad);
}
}
}
到目前爲止,唯一的想法,我們可以拿出以確定性得到RCW釋放其在這種情況下引用的將是重新工作的引擎,使所有的接口都有一個不時調用Cleanup()調用,但這會很耗時,並且在某些情況下,實現起來非常麻煩。
tl; dr有沒有辦法強制RCW釋放其對正在返回到非託管環境的COM對象的引用?
'IDoodad'應該繼承'IUnknown',所以你應該能夠通常調用'Release'最後我檢查 – Mgetz
發佈遞減引用計數。如果其他東西(RCW)仍然有參考價值,那麼塗鴉就會繼續存在。在上面的代碼中,我暗示IDoodadPtr是一個智能指針,它在超出範圍時調用Release。 – Alias
你的意思是[COM Callable Wrapper](http://msdn.microsoft.com/en-us/library/f07c8z1c.aspx)?根據MSDN,如果正常調用發行版,它將釋放垃圾收集對象。 – Mgetz