【发布时间】:2010-09-15 01:58:34
【问题描述】:
真的有必要通过调用 Marshal.ReleaseComObject(..) 从 Office PIA 释放 COM 组件吗?
我在网上找到了关于这个主题的各种相互矛盾的建议。在我看来,由于 Outlook PIA 总是返回对其接口的新引用作为其方法的返回值,因此没有必要显式释放它。我说的对吗?
【问题讨论】:
标签: c# .net outlook add-in pia
真的有必要通过调用 Marshal.ReleaseComObject(..) 从 Office PIA 释放 COM 组件吗?
我在网上找到了关于这个主题的各种相互矛盾的建议。在我看来,由于 Outlook PIA 总是返回对其接口的新引用作为其方法的返回值,因此没有必要显式释放它。我说的对吗?
【问题讨论】:
标签: c# .net outlook add-in pia
有一些好的做法here 使用托管包装器..值得一试..
【讨论】:
也许这只是我的迷信,但我决定通过 Marshal.ReleaseComObject() 明确发布 Office PIA,因为当我的应用程序崩溃时,对 Excel 和 Word 的引用保持打开状态。我没有深入挖掘原因(愚蠢的截止日期),但将它们作为我班级的处置模式的一部分发布解决了这个问题。
【讨论】:
PIA 是 .NET 互操作包装器。这意味着在对象的析构函数(或 Dispose - 我不记得了)会自动处理它的引用计数。诀窍是在执行垃圾收集器之前不会释放一些引用。这取决于 COM 对象实例化的内容。例如,打开数据库游标的 COM 对象将使这些游标在内存中保持活动状态,直到这些游标上的引用计数被释放。使用 .NET/COM 互操作,在垃圾收集器执行或使用 Marshal.ReleaseComObject(或 FinalReleaseComObject)显式释放引用之前,不会释放引用。
我个人没有使用过 Microsoft Office PIA,但在大多数情况下,您不应该必须明确发布引用。只有当您的应用程序开始锁定其他资源或崩溃时,您才应该开始怀疑悬空引用。
编辑:如果您遇到确实需要清理 COM/Interop 对象的情况,请使用 Marshal.FinalReleaseComObject - 它将引用计数一直为零,而不是仅递减 1 - 并将对象引用设置为 null。如果您真的想要安全,则可以显式强制垃圾回收 (GC.Collect),但要小心不要过于频繁地执行 GC,因为它会导致明显的性能损失。
【讨论】:
如果您希望 Office 应用程序的实例退出,您确实需要这样做,如this post 中所述。
除了最简单的情况外,很难在所有情况下都做到正确。
【讨论】:
对于 Microsoft Office,一般来说,您确实需要明确发布您的参考资料,这可以分两个阶段安全地完成:
(1) 首先通过调用 GC.Collect() 然后调用 GC.WaitForPendingFinalizers() 释放所有您不持有命名对象变量的次要对象。 (如果涉及的对象可能具有终结器,例如在使用 Visual Studio Tools for Office (VSTO) 时,您需要调用它两次。)
(2) 然后通过在每个对象上调用 Marshall.FinalReleaseComObject() 显式释放您持有命名变量的对象。
就是这样。 :-)
我更详细地讨论了这个 in a previous post,以及一个代码示例。
【讨论】:
我的经验表明您必须这样做,否则(至少是 Outlook)应用程序可能根本不会关闭。
但这又会引发另一波蠕虫,因为看起来 RCW 是每个进程的,因此您可以破坏其他一些插件,这些插件恰好具有对同一对象的引用。
我已经发布了一个相关的问题here,但我仍然没有明确的答案。一旦我知道更多,我会编辑这篇文章。
【讨论】:
关于 .Net/COM 互操作有一个简单的规则 - 如有疑问,请始终使用 Release()。 :-)
【讨论】:
对于 VS 2010,请参阅 Marshal.ReleaseComObject Is Considered Dangerous。
【讨论】: