问题描述
我知道基本区别,因为 ReleaseComObject
仅将某个计数器减一,而 FinalReleaseComObject
将其减为零.
I know the basic difference as ReleaseComObject
only decreases some counter by one and FinalReleaseComObject
decreases it to zero.
所以我通常听到的是,调用 FinalReleaseComObject
因为这样你就确定 COM 对象真的被释放了.
So what I usually hear is, call FinalReleaseComObject
because then you are sure that the COM object is really released.
但这让我想知道,这个计数器有一个点对吗?如果你总是调用FinalReleaseComObject
,你是不是破坏了这个机制.如果在您调用 ReleaseComObject
之前该计数器不是 one,那么可能没有原因吗?
But this makes me wonder, there is a point to this counter right? Aren't you breaking that mechanism if you always call FinalReleaseComObject
. If that counter is not one before you call ReleaseComObject
, is there not probably a reason for it?
什么可能导致它不应该高于一?
What could cause it to be higher than one when it should not be?
提前致谢.
PS:我的 COM 经验只包括使用 Excel 互操作.不确定这个问题是否是该域的本地问题(即在 Office Interop 之外,FinalReleaseComObject
不经常使用).
PS: My COM experience only consists of using Excel Interop. Not sure if this question is local to that domain (i.e. outside Office Interop, FinalReleaseComObject
is not often used).
文章 Dan提到的关于使用<代码>ReleaseComObject 完成后.正如我从 文章 中了解到的,这是正常的大大地.我认为,如果您始终如一地这样做,它应该可以正常工作.在对文章的评论中,作者建议某人循环调用 ReleaseComObject
直到它真正被释放(article 来自 2006 年,所以这类似于调用 FinalReleaseComObject
).但他也表示这可能很危险.
The article Dan mentioned talks about using ReleaseComObject
when you're done. As I understand from the article, this is the normal way. I think that if you do this consistently it should work fine. In a comment to the article the author suggests someone to call ReleaseComObject
in a loop until it is really released (the article is from 2006, so this is analogues to calling FinalReleaseComObject
). But he also states that this could be dangerous.
如果您确实希望 RCW 在代码中的特定点调用 Release(),您可以在循环中调用 ReleaseComObject(),直到返回值达到零.这应该确保 RCW 将调用 Release().但是,如果您这样做,请注意,当其他托管引用尝试使用该 RCW 时,将导致异常."
If you really want to the RCW to call Release() at a particular point in the code, you can call ReleaseComObject() in a loop until the return value reaches zero. This should ensure the RCW will call Release(). However, if you do that, be warned, when the other managed references try to use that RCW, it will cause an exception."
这让我相信总是调用 FinalReleaseComObject
确实不是一个好主意,因为你可能会在其他地方引发异常.正如我现在所看到的,只有在绝对确定可以调用时才应该调用它.
This leads me to believe that it is indeed not a good idea to always call FinalReleaseComObject
, as you can cause exceptions elsewhere. As I see it now, you should only call this if you are absolutely sure that you can.
不过,我在这方面的经验很少.我不知道我怎么能确定.如果计数器在不应该增加的时候增加,解决这个问题不是更好吗?如果是这样,那么我会说 FinalReleaseComObject
与其说是最佳实践,不如说是一种技巧.
Still, I have little experience in this matter. I don't know how I can be sure. If the counter is increased when it should not be, is it not better to fix that problem? If so, then I would say FinalReleaseComObject
is more of a hack than a best practice.
推荐答案
一些序言...
运行时可调用包装器 (RCW) 仅在其包装的非托管 COM 接口上调用 IUnknown.AddRef 一次.但是,RCW 还维护对 RCW 本身的托管引用数量的单独计数.调用 Marshal.ReleaseComObject 会减少托管引用的这个单独计数.当托管引用的计数达到零时,RCW 在非托管 COM 接口上调用 IUnknown.Release 一次.
A Runtime Callable Wrapper (RCW) only calls IUnknown.AddRef once on the unmanaged COM interface that it wraps. However, an RCW also maintains a separate count of the number of managed references there are to the RCW itself. It is this separate count of managed references that is decremented by a call to Marshal.ReleaseComObject. When the count of managed references reaches zero, the RCW calls IUnknown.Release once on the unmanaged COM interface.
Marshal.FinalReleaseComObject 通过一次调用将托管引用计数归零,因此立即调用封装的非托管 IUnknown.Release 方法(假设托管引用计数尚未为零).
Marshal.FinalReleaseComObject takes the managed reference count to zero with a single call, and thus invokes the wrapped unmanaged IUnknown.Release method immediately (assuming that the managed reference count was not already zero).
那么为什么 Marshal.ReleaseComObject 和 Marshal.FinalReleaseComObject 都有呢?调用 Marshal.FinalReleaseComObject 只是避免了编写一个循环来重复调用 Marshal.ReleaseComObject 直到它返回 0,当你希望表明你真的已经完成使用 COM 对象现在.
So why have both Marshal.ReleaseComObject and Marshal.FinalReleaseComObject? Calling Marshal.FinalReleaseComObject simply avoids having to write a loop that calls Marshal.ReleaseComObject repeatedly until it returns 0 when you wish to indicate that you've really finished using a COM object now.
为什么要使用 Marshal.ReleaseComObject 或 Marshal.FinalReleaseComObject?我知道有两个原因:
Why use either Marshal.ReleaseComObject or Marshal.FinalReleaseComObject? There are two reasons I'm aware of:
首先是确保被包装的 COM 对象使用的非托管资源(如文件句柄、内存等)在调用非托管 IUnknown.Release() 方法后尽快释放.
The first is to ensure that unmanaged resources (such as file handles, memory etc.) being used by the wrapped COM object are freed as soon as possible as a result of the resulting call to the unmanaged IUnknown.Release() method.
第二个是确保调用非托管 IUnknown.Release() 方法的线程在你的控制之下,而不是终结器线程.
The second is to ensure that the thread calling the unmanaged IUnknown.Release() method is under your control, and not the finalizer thread.
如果不调用这些 Marshal 方法中的任何一个,RCW 的终结器将最终在 RCW 被垃圾回收后的某个时间调用非托管 IUnknown.Release() 方法.
Without calls to either of these Marshal methods, the RCW's finalizer will eventually call the unmanaged IUnknown.Release() method some time after the RCW has been garbage collected.
有关确凿的详细信息,请参阅 Visual C++ 团队博客条目 混合确定性和非确定性清理
For corroborative details, see the Visual C++ Team blog entry Mixing deterministic and non-deterministic cleanup
这篇关于为什么使用 FinalReleaseComObject 而不是 ReleaseComObject?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!