假设我有一个COM对象(非托管)和.NET客户端。
是否需要从.NET客户端Marshal.FinalReleaseComObject
方法调用才能释放COM对象?
答案 0 :(得分:2)
没有。无需从.Net客户端显式释放COM对象。 COM对象将像任何其他.Net对象一样被收集,并且一旦删除了对它的所有引用,它将释放它的底层本机句柄。
明确使用FinalReleaseComObject
实际上会导致编程错误。如果代码中的另一个组件仍然引用COM对象,那么您将从其下面取出本机对象。这可能会导致运行时故障。
答案 1 :(得分:2)
已修改“是”,以及“否”。
首先,请记住ReleaseComObject
不会自动减少真正的COM对象引用次数。相反,它减少了内部RCW计数器。 (每次从COM-> NET移动相同的 COM对象时,它将使用相同的 RCW并将RCW计数器递增1。)同样,{{1}也会影响RCW对手有效地“将其设置为0”。当RCW计数器变为零时,.NET将减少实际 COM引用计数。
所以,“是”,但针对这些规则进行了修改 :
FinalRelaseComObject
,但不是 {{1} ,调用它。也就是说,每次对象交叉时都应该调用一次 ,即使它导致引用等于RCW 。我说上面的规则和不 ReleaseComObject
因为RCW对象被缓存在身份代理中,所以使用FinalReleaseComObject
会影响COM- > NET边界交叉,你甚至不知道 ! (这很糟糕,在这一点上,我完全同意JaredPars的回答。)
“no”,当RCW被回收(终结者被调用)时,它将自动“释放”COM引用(有效地调用{{ 1}}本身)。请记住,因为只有一个RCW对象,这意味着只要在.NET中引用它就永远不会回收。如果RCW被回收,则没有问题,因为从上面来看,没有更多对RCW的引用,因此.NET知道它可以将COM引用减少1(这可能会导致COM要销毁的对象。)
但是,由于.NET GC很挑剔并且非确定性,因此依赖此行为意味着对象生命周期不受控制。例如,在使用Outlook对象模型时,这可能会导致许多细微问题。 (它可能不太容易出现其他COM服务器的问题,但是OOM在内部对对象进行了有趣的“缓存”。当不明确地控制生命期时,很容易得到“项目已被修改”异常。)
在我的代码中,我有一个支持FinalReleaseComObject
的{{1}}类。这允许我通过清除生命周期所有权传递从COM-> NET获得的RCW对象。在切换到这种方法和众多问题之后,我在Outlook-Addin开发中遇到的问题很少(实际上几乎没有)。 “缺点”是需要确定COM-> NET边界,但一旦确定,则内部所有生命周期都得到正确处理。
快乐的编码。