我能得到一些关于ReleaseComObject的清晰度吗?我能忽略它吗?

本文关键字:清晰度 ReleaseComObject | 更新日期: 2023-09-27 18:09:29

我已经在VBA中开发了一段时间的办公解决方案,并且对VBA中的办公开发有相当完整的了解。我已经决定是时候用。net学习一些真正的编程了,我有一些初期的问题。

看了一堆文章和论坛(这里和其他地方),似乎有一些关于。net中使用COM对象时内存管理的混合信息。

有些人说我应该总是确定性地释放COM对象,而另一些人说我几乎不应该这样做。

人们说我应该这样做:

《Professional Excel Development》一书,第861页。

这个栈交换问题的答案是"你对COM对象的每个引用都必须被释放"。如果不这样做,进程将留在内存中"

这个博客建议用它来解决他的问题。

人们说我不应该这样做:

Eric Carter的MSDN博客指出:"在VSTO场景中,通常不需要使用ReleaseCOMObject。"

Eric Carter合著的《VSTO for Office 2007》一书似乎没有提到任何内存管理或ReleaseComObject。

Paul Harrington的MSDN博客说不要这样做。

有人给出了复杂的建议:

Jake Ginnivan说我应该总是在不离开方法作用域的COM对象上这样做。如果一个COM对象离开了方法作用域,那么忘掉它吧。为什么我就不能一直忘记它呢?

Paul Harrington的博客似乎表明MS的建议在过去的某个时候发生了变化。它的情况下,调用ReleaseCOMObject过去是最佳实践,但不再是吗?我可以把内存管理的细节留给MS,并假设一切都会很好吗?

我能得到一些关于ReleaseComObject的清晰度吗?我能忽略它吗?

我尝试在我的关于ReleaseComObject的互操作开发中遵循以下规则。

如果我的托管对象实现了某种类似于IDisposable的关闭协议,我在我持有引用的任何子COM对象上调用ReleaseComObject。我正在讨论的关闭协议的一些示例:

  • IObjectWithSite.SetSite(null)
  • IOleObject.SetClientSite(null)
  • IOleObject.Close()
  • IDTExtensibility2.OnDisconnection
  • IDTExtensibility2.OnBeginShutdown

  • IDisposable.Dispose本身

这有助于打破。net和本机COM对象之间潜在的循环引用,因此托管垃圾收集器可以不受阻碍地完成其工作。

也许,有一些类似的东西可以在你的VSTO互操作场景中使用(AFAIR, IDTExtensibility2在那里相关)。

如果互操作场景涉及IPC COM调用(例如,当您将托管事件接收器对象传递给进程外COM服务器(如Excel)时),则有另一个选项来跟踪对托管对象的外部引用:IExternalConnection接口。IExternalConnection::AddConnection/ReleaseConnectionIUnknown::AddRef/Release非常相似,但是当从另一个COM公寓(包括驻留在单独进程中的公寓)添加引用时,它们会被调用。

IExternalConnection为进程外场景提供了一种实现几乎通用的关闭机制的方法。当外部引用计数达到零时,你应该在你可能持有引用的任何外部Excel对象上调用ReleaseComObject,有效地打破进程和Excel进程之间任何潜在的循环COM引用。也许,像这样的东西已经被VSTO运行时实现了(我对VSTO没有太多的经验)。

也就是说,如果没有明确的关闭机制,我就不调用ReleaseComObject。此外,我从不使用FinalReleaseComObject .

您不应该忽略它,如果您正在使用Office GUI!就像你的第二个链接状态:

对COM对象的每个引用都必须被释放。如果不这样做,进程将留在内存中。

这意味着,如果您不显式释放对象,则对象将保留在内存中。因为它们是COM对象,所以垃圾收集器负责释放它们。然而,Excel和其他花哨的工具是在不了解。net中的垃圾收集器的情况下实现的。它们与记忆的确定性释放有关。如果你正在从excel请求一个对象,而没有正确释放它,这可能是你的应用程序没有正确关闭,因为它等待,直到你的资源被释放。如果您的对象存在的时间足够长,可以进入gen1或gen2,那么这可能需要几个小时甚至几天的时间!

关于不释放COM对象的所有考虑都是针对多线程场景或在多个实例上被迫推送许多COM对象的场景。作为一个好的建议,总是尽可能晚地创建com对象,并以与创建相反的顺序尽快释放它们。此外,您还应该考虑尽可能保持互操作实例的私密性。这减少了其他线程或实例在您已经释放对象时访问该对象的可能性。