应该以什么顺序释放COM对象和垃圾收集?

时间:2012-11-26 19:47:45

标签: c# com garbage-collection

有很多关于释放COM对象和垃圾收集的问题,但我没有找到具体解决这个问题的任何问题。

当释放COM对象(在本例中特别是Excel Interop)时,我应该以什么顺序释放引用并调用垃圾收集?

在某些地方(例如here)我看到了这个:

Marshall.FinalReleaseComObject(obj);
GC.Collect();
GC.WaitForPendingFinalizers();

而在其他人(例如here)中:

GC.Collect();
GC.WaitForPendingFinalizers();
Marshall.FinalReleaseComObject(obj);

或者不重要,我什么都不担心?

2 个答案:

答案 0 :(得分:4)

Marshal.FinalReleaseComObject()释放底层的COM接口指针。

GC.Collect()和GC.WaitForPendingFinalizers()导致调用COM包装器的终结器,调用FinalReleaseComObject()。

所以没有意义的是两种方式。选择其中一个。

显式调用FinalReleaseComObject()的麻烦在于它只能在为所有接口指针调用它时才能工作。如果您错过其中一个,Office程序将继续运行。那个非常很容易做到,特别是C#版本4中允许的语法糖使其成为可能。像range = sheet.Cells[1, 1]这样的表达式,在Excel互操作代码中很常见。那里有一个隐藏的Range接口引用,你永远不会明确地存储在任何地方。所以你也不能发布它。

这不是GC.Collect()的问题,它可以看到它们。然而,它并非完全没有问题,它只会在你的程序不再引用接口时收集并运行终结器。这肯定是你的第二个片段的错误。调试程序时,调试器往往会出错,调试器会将本地对象引用的生命周期延长到方法的末尾。还有你看看Taskmgr并大喊“死该死!”的时间。

GC.Collect()的常用建议也适用于此处。让您的程序保持运行并执行工作。通常情况下,您将触发垃圾收集并释放COM包装器。 Office程序将退出。它不会立即发生,最终会发生。

答案 1 :(得分:1)

COM使用的引用计数机制是另一种自动内存管理方式,但对内存和行为的影响略有不同。

任何引用计数实现都为资源清理提供了确定性行为。这意味着在调用Marshal.FinalReleaseComObject()之后,将回收与COM对象相关的所有资源(内存和其他资源)。

这意味着如果我们有其他托管对象,并且您希望尽快回收它们,则应首先释放COM对象,并且仅在调用GC.Collect方法之后。