我正在开发一个Outlook Addin,我创建了很多COM对象(Outlook邮件,Outlook文件夹等)。我的理解是,由于这些对象是COM对象,CLR不会从这些对象释放内存,我将不得不照顾从这些对象释放内存。所以要从这些对象释放内存我使用
Marshal.ReleaseComObject的(对象);
但不幸的是,这似乎没有用。然后我在Marshal.ReleaseComObject(Object)之后放了一个GC.Collect()语句;并且这个工作。之后我没有得到任何与内存相关的异常。 我的问题是,如果CLR可以从COM对象中重新调用内存,为什么它不能单独执行。如果它不能,那么GC.Collect()语句在我的情况下是如何工作的。
答案 0 :(得分:7)
为了将COM与.Net一起使用,您需要对Runtime Callable Wrapper有一个很好的理解。基本上,你的.Net代码中的所有内容都是对COM对象的引用,实际上是对RCW的引用。 RCW通过计算底层COM对象的引用数量来管理它的引用计数,当它上的引用计数降为0时,它将在底层对象上调用Release
(一次)。当RCW处于活动状态时,它将在COM对象上保持单个引用。
ReleaseComObject
API会将RCW上的引用计数减少1.如果这会使RCW上的引用计数为0,则RCW将在COM对象上调用Release
,否则不会。还有FinalReleaseComObject
会导致RCW上的引用计数变为0(从而导致RCW调用Release
)尽管如果你在RCW上有其他未完成的参考,这是有风险的他们可能会犯错误。
“正常”,当引用它的对象被垃圾收集时,RCW上的引用被管理 - 这可以解释为什么在强制垃圾收集时看到COM对象被释放的原因。这与我们对RCW如何工作的了解相结合,告诉我们RCW上还有其他参考资料,您也需要“{需要”调用ReleaseComObject
以使其Release
。
调用ReleaseComObject
是围绕.Net运行时的最终运行,您必须非常小心地管理所有创建的引用。创建的一些引用是“隐式”引用 - 这些引用的原因是调用返回引用的属性,然后调用它们。当你做这样的事情时,这有时被称为“太多点”问题:
object.foo.blah.baz.something()
“foo”,“blah”和“baz”可能都是某些需要考虑的COM对象的引用。
答案 1 :(得分:0)
您是否尝试在Marshal.ReleaseComObject之后分配内存?因为,你知道,垃圾收集器将按照自己的意愿运行,这通常意味着在分配内存时,而不仅仅是当你认为它应该运行时(当然,除非你调用GC.Collect)。
到目前为止,我没有自动释放COM对象的任何问题,只有在我希望COM服务器立即关闭时才调用Marshal.ReleaseComObject。