我在网上阅读了很多关于安全发布 RCW 的文章,在我看来,没有人能就具体需要按什么顺序完成的事情达成一致,所以我想请教各位大佬的意见。例如,可以这样做:
object target = null;
try {
// Instantiate and use the target object.
// Assume we know what we are doing: the contents of this try block
// do in fact represent the entire desired lifetime of the COM object,
// and we are releasing all RCWs in reverse order of acquisition.
} finally {
if(target != null) {
Marshal.FinalReleaseComObject(target);
target = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
但是,有些人主张在
Marshal.FinalReleaseComObject
之前进行垃圾收集。 ,有的在之后,有的根本没有。真的有必要手动 GC 每一个 RCW,尤其是在它已经从它的 COM 对象中分离出来之后?在我看来,将 RCW 从 COM 对象中分离出来并让 RCW 自然过期会更简单、更容易:
object target = null;
try {
// Same content as above.
} finally {
if(target != null) {
Marshal.FinalReleaseComObject(target);
}
}
这样做就足够了吗?
最佳答案
要释放您对 objective-c OM 对象的引用, 就足够了和首选只需调用Marshal.FinalReleaseComObject
和 不是 强制收集。换句话说,您已经履行了在完成引用后立即发布引用的责任。 FinalReleaseComObject
的问题我就不说了对比 ReleaseComObject
.
这就留下了一个更大的问题,为什么人们提倡调用 GC.Collect()
。和 WaitForPendingFinalizers()
?
因为对于某些设计,很难知道何时不再有托管引用,因此您无法安全地调用 ReleaseComObject
.你有两个选择,让内存建立起来,希望收集发生或强制收集。 [见评论中史蒂文詹森的反对票]
另一个注意事项是设置 target
至null
通常是不必要的,特别是在您的示例代码中是不必要的。将对象设置为空是 VB6 的常见做法,因为它使用基于引用计数的垃圾收集器。 C# 的编译器足够聪明(在构建发布时)知道 target
在最后一次使用后无法访问,并且可能会被 GC,甚至在离开范围之前。最后一次使用是指最后一次可能的使用,因此在某些情况下您可以将其设置为 null
.您可以使用以下代码自己查看:
using System;
class GCTest
{
~GCTest() { Console.WriteLine("Finalized"); }
static void Main()
{
Console.WriteLine("hello");
GCTest x = new GCTest();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("bye");
}
}
如果您构建版本(例如,CSC GCTest.cs),“Finalized”将在“hello”和“bye”之间打印出来。如果您构建调试(例如,CSC/debug GCTest.cs),“Finalized”将在“再见”之后打印出来,而设置
x
在 Collect()
之前为空会“解决”这个问题。
关于.net - 从 .NET 安全地释放 COM 对象引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1834950/