Ric*_*lly 6 c# clr destructor .net-4.0 finalizer
虽然"调查"最终确定(阅读:尝试愚蠢的事情)我偶然发现了一些意想不到的行为(至少对我来说).
我原本期望Finalize方法不被调用,而它被调用两次
class Program
{
static void Main(string[] args)
{
// The MyClass type has a Finalize method defined for it
// Creating a MyClass places a reference to obj on the finalization table.
var myClass = new MyClass();
// Append another 2 references for myClass onto the finalization table.
System.GC.ReRegisterForFinalize(myClass);
System.GC.ReRegisterForFinalize(myClass);
// There are now 3 references to myClass on the finalization table.
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
// Remove the reference to the object.
myClass = null;
// Force the GC to collect the object.
System.GC.Collect(2, System.GCCollectionMode.Forced);
// The first call to obj's Finalize method will be discarded but
// two calls to Finalize are still performed.
System.Console.ReadLine();
}
}
class MyClass
{
~MyClass()
{
System.Console.WriteLine("Finalise() called");
}
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释这种行为是否是故意的,如果是这样,为什么
上面的代码是在x86调试模式下编译的,并在CLR v4上运行.
非常感谢
Eri*_*ert 16
我不知道是什么导致了奇怪的行为.但是,由于您违反了该方法的记录用法,因此可能发生任何事情.ReRegisterForFinalize的文档说:
请求系统调用先前已调用SuppressFinalize的指定对象的终结器.
在调用ReRegisterForFinalize之前,您之前没有调用SuppressFinalize.文档没有说明在那种情况下会发生什么,事实上,显然发生了一些非常奇怪的事情.
不幸的是,相同的文档页面继续显示一个示例,其中在尚未调用SuppressFinalize的对象上调用ReRegisterForFinalize.
这有点乱.我将与文档管理员联系.
当然,这个故事的寓意是,当你违反文档中描述的规则时会受到伤害,然后停止违反它们.
Jon*_*eet 10
我猜 ...这真的是只是一种猜测.正如埃里克所说,不要违反这样的规则:)这个猜测只是为了闲置的猜测和兴趣.
我怀疑涉及两种数据结构:
当GC注意到一个对象有资格进行垃圾收集时,我怀疑它会检查对象的头并将引用添加到终结队列.你的电话SuppressFinalization会阻止这种行为.
另外,终结器线程遍历终结队列并为找到的所有内容调用终结器.您的呼叫ReRegisterForFinalize绕过了引用最终在队列中的正常方式,并直接添加它.SuppressFinalization没有从队列中删除引用 - 它只是停止以正常方式将引用添加到队列中.
所有这些都可以解释你所看到的行为(以及我所复制的行为).这也解释了为什么当我删除SuppressFinalization电话我最终看到称为终结3倍-因为在这种情况下,"正常"的路径添加参考终结队列为好.
有趣的数据点:
Win32上的mono 2.6.7不会调用终结器
Win32上的.NET 3.5调用终结器两次
测试代码供参考:
class Program
{
static void Main(string[] args)
{
// The MyClass type has a Finalize method defined for it
// Creating a MyClass places a reference to obj on the finalization table.
var myClass = new MyClass();
// Append another 2 references for myClass onto the finalization table.
System.GC.ReRegisterForFinalize(myClass);
System.GC.ReRegisterForFinalize(myClass);
// There are now 3 references to myClass on the finalization table.
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
System.GC.SuppressFinalize(myClass);
// Remove the reference to the object.
myClass = null;
// Force the GC to collect the object.
System.GC.Collect(2, System.GCCollectionMode.Forced);
// The first call to obj's Finalize method will be discarded but
// two calls to Finalize are still performed.
}
}
class MyClass
{
~MyClass()
{
System.Console.WriteLine("Finalise() called");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1015 次 |
| 最近记录: |