Chr*_*ter 6 .net com-interop rcw
我已经在网上阅读了很多关于安全发布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();
}
}
Run Code Online (Sandbox Code Playgroud)
然而,有些人主张在之前进行垃圾收集Marshal.FinalReleaseComObject,有些人在之后,有些则根本没有.是否真的有必要手动GC每个RCW,特别是在它已经从COM对象中分离出来之后?
在我看来,将RCW从COM对象中分离并让RCW自然过期会更简单,更容易:
object target = null;
try {
// Same content as above.
} finally {
if(target != null) {
Marshal.FinalReleaseComObject(target);
}
}
Run Code Online (Sandbox Code Playgroud)
这样做是否足够?
Ton*_*Lee 12
为了使您参考发布的目标COM对象,它是足够的和优选只是调用Marshal.FinalReleaseComObject并没有强制收集.换句话说,您已经完成了在完成参考后立即发布参考的责任.我不会触及FinalReleaseComObjectvs 的问题ReleaseComObject.
这留下的,为什么人们主张调用更大的问题GC.Collect()和WaitForPendingFinalizers()?
因为对于某些设计,很难知道何时没有更多托管引用,因此您无法安全地调用ReleaseComObject.你有两个选择,让内存积累并希望收集发生或强制收集.[请参阅评论中的Steven Jansen的投票说明]
另外一个值得注意的是,设置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");
}
}
Run Code Online (Sandbox Code Playgroud)
如果你构建版本(例如,CSC GCTest.cs),"Finalized"将在"hello"和"bye"之间打印出来.如果你构建调试(例如,CSC/debug GCTest.cs),"Finalized"将在"bye"之后打印出来,而x在之前设置为null Collect()将会"修复"它.