Finalize,即.NET类型的非确定性析构器,将在对象被GC检查回收前调用。现在我关心一个问题,值类型,一般是自定义struct的析构器会不会被调用呢?一般值类型是在栈上分配,因此就不在托管堆上,不存在被GC回收的情况。但是我们要是将值类型装箱以后放在托管堆里了呢?他的析构器会不会被调用呢?由于C#和C++对析构器语法特别对待,我们不能在struct里面直接重写Finalize方法,因此这个实验只能用VB来做: Public Structure A Public i As Integer
Protected Overrides Sub Finalize() MsgBox("Hi, finalized") End Sub End Structure 在这个类里面,我们名目张胆地重写了Finalize,并且没有调用基类的Finalize,幸好VB对这种行为视而不见。首先我们检查是不是真的成功重写了基类的方法,用以下代码测试一下: Dim x As Object = New A
GetType(Object).GetMethod("Finalize", BindingFlags.NonPublic Or _ BindingFlags.Instance _ ).Invoke(x, New Object() {}) 结果顺利显示了结果。接下来就进入主题,将该装箱后的对象抛弃在托管堆中,然后调用GC.Collect回收,看看是否能启动Finalize: Dim x As Object = New A
x = Nothing GC.Collect() 结果……没有运行!?难道是这段代码无法达成调用Finalize的条件?我将Structure换成Class试试看,结果马上显示Finalize被调用了。这说明Finalize对值类型确实不管用。那么是不是因为CLR内部在某处对值类型自动调用GC.SuppressFinalize之类的方法注销了Finalize呢?那好,我们就多给他注册几个试试: Dim x As Object = New A
GC.ReRegisterForFinalize(x) GC.ReRegisterForFinalize(x) ......
x = Nothing GC.Collect() 结果,不管写了几次GC.ReRegisterForFinalize,在GC回收x的时候仍然没有Finalize运行的踪迹。看来,在CLR内部,值类型的Finalize是有特定规则的,不按照一般类的方式运行。我也没研究CLR的机制,没法再深究这个过程原理,以后有机会要好好看看…… |