【问题标题】:When do I need to call ReleaseComObject?我什么时候需要调用 ReleaseComObject?
【发布时间】:2012-05-08 00:48:56
【问题描述】:

在 Microsoft Office 插件中,我们通过事件传递 COM 对象。举一个特定的例子,当 Word 打开一个文档时,我们被调用并传递了一个 Document 对象。那么我们什么时候需要调用 Marshal.ReleaseComObject() 呢?

  1. 如果我们访问 Document 对象,是否需要对其调用 release?或者我们可以假设 Word 已经访问过它并会清理它吗?
  2. 如果我们访问给我们一个字符串的 Document.Name。由于字符串不是 COM 对象,我们不需要清理它 - 对吗?
  3. 但是,如果我们访问返回包装 COM 对象的类的任何成员(即由成员方法/函数返回的任何类),我们确实需要调用 release - 对吗?

如果我们错过一个版本会发生什么?我们持有的任何 COM 对象的时间不确定,我们将其包装在一个实现了 IDisposable 的类中。完成后我们调用 Dispose()。但是处理这个问题的一些代码很复杂,我猜我们偶尔会遇到不调用 Dispose 的情况。

我们最好有一个终结器,然后为这些对象的每个实例增加开销(很多!)?还是我们最好使用少量从未释放的 Word COM 对象?

谢谢 - 戴夫

【问题讨论】:

  • 关于这个的问题已经有数百个,通过方法名很容易找到。一遍又一遍的相同主题,RCW 是一个托管对象,因此遵守垃圾回收生命周期规则。你用 GC.Collect 强制收集
  • 我在 S/O 上通读了 12 个项目。以上是我阅读完所有这些后留下的问题。 MS Office COM 对象有点复杂,因为您不确定 Office 到底在做什么。
  • COM只有一种,Office没有使用它的特殊版本。对象模型越复杂,用 ReleaseComObject 打猴子的可能性就越小。这就是为什么你把它留给垃圾收集器,它永远不会错过任何一只猴子。
  • 黑魔法在软件工程中没有立足之地。使用 C# 版本 4 中允许的语法扩展,还有很多方法可以错过猴子。 Range.Cell[x, y].Value 语法非常适合隐藏 3 只完全不可打孔的猴子,因为你没有在任何地方分配接口引用。这就是为什么你把它留给垃圾收集器。
  • 是的,这是一种非常流行的错觉。否则,这并不能使它成为正确的错觉。只有沙华鱼人做对了。这种情况一遍又一遍地出现,因为每个人都在做错事,这是很难避免的。出于完全相同的原因,编写一个不泄漏内存的 C 程序很难做到。显然我无法说服你,这并不重要。通过发布一个显示问题的 sn-p 来使这个问题成为一个真正的问题。

标签: .net com office-interop


【解决方案1】:

简而言之,必须释放对 COM 对象的每个引用。如果不这样做,该过程将保留在内存中。

排除值类型(字符串等)和您未明确引用的子 COM 对象。

一个例外可能是作为事件参数传递给您的 COM 对象。我认为您不需要释放它们,但我不确定。但是,快速测试应该可以证实这一点。 (在释放和不释放 COM 对象的情况下尝试您的加载项。查看加载项是否开始表现得滑稽,或者在应用关闭后是否有任何相关进程仍在运行。)

解决您的具体问题:

  1. 如果我们访问 Document 对象,是否需要对其调用 release?或者我们可以假设 Word 已经访问过它并会清理它? -- 你必须释放它。

  2. 如果我们访问给我们一个字符串的 Document.Name。由于字符串不是 COM 对象,我们不需要清理它 - 对吗? -- 你不需要清理值类型。

  3. 但是,如果我们访问返回包装 COM 对象的类的任何成员(这是由成员方法/函数返回的任何类),我们确实需要调用 release - 对吗? -- 如果你没有明确引用它,你不需要释放它。 (有一些例外。例如,在question of mine 中,我发现一个特定的 COM 方法正在实例化一个 COM 对象并且从不释放它。由于我无法控制方法的实现,我唯一的选择是避免使用该方法。)

  4. 如果我们错过发布会怎样? -- 进程(winword.exe、excel.exe 等)将保留在内存中。随着时间的推移,所有这些未终止的进程都会耗尽机器上的所有可用内存。

  5. 我们最好有一个终结器,然后为这些对象的每个实例增加开销(很多!)?还是我们最好使用少量从未发布的 Word COM 对象? -- 你最好使用终结器。总是释放你的 COM 对象!我发现here 列出的步骤是最有效的。 (这些步骤使用 FinalReleaseComObject,它比 ReleaseComObject 更受欢迎。)我还建议不要杀死 Office 进程作为不释放 COM 的替代方法。随着时间的推移,这将导致 Office 互操作出现问题(我从未完全理解)。

【讨论】:

  • 首先谢谢您!其次,关于问题 1,当我访问 Document 对象时,它会被编组,这就是我需要释放它的原因吗?释放传递给我的对象感觉不对。这并不意味着它是错误的,但感觉就是这样。
  • 抱歉,我错过了 Document 对象通过事件参数传递给您的事实。我更新了我的问题来解决这个问题。您使用什么来创建加载项?你没有使用 VSTO?
  • 我们将旧的 IExtensibility API 用于我们的加载项。回到我们开始 VSTO 的时候真的很有限(现在不知道)。在尝试发布时,看看它是否变得松散 - 这往往会导致问题。
  • 经过更多研究后,我几乎可以肯定您不需要释放作为事件参数传递给您的 COM 对象。这就是它与 VSTO 项目的工作方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 2013-05-21
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2018-02-25
相关资源
最近更新 更多