Finalization

 

Finalization是CLR提供的一种机制。简单的说,类型实现了一个命名为Finalize的方法,当垃圾回收期判断对象是一个垃圾时,会调用对象的Finalize的方法(如果有的话)在C#中,类名前加上~来定义Finalize方法。编译器自动将这种函数转换为Object.Finalize的一个override。

例如:

class tally

{

~tally(){};

}

会被转换为

class tally

{

protected override void Finalize()

{

try{}

finally{base.Finalize();}

}

}

try finally结果,保证了,总是能调用父类的finalize方法。只有编译器才能这样转换,我们无法自行覆盖这种Finalize,也不能调用Finalize

在C++中,这种定义被称为析构函数,它会被确定性的析构。

但是在.net中,这种析构函数是不确定的,也就是说不知道什么时候会发生

Finalize方法再垃圾回收时运行,而垃圾回收可能在应用程序请求更多内存时发生。CLR不保证各个Finalize方法的调用顺序。

Finalize方法再垃圾回收结束时调用,有以下5种时间会导致开始垃圾回收

第0代满

代码显示调用System.GC

Windows报告内存不足

CLR卸载AppDomain

CLR关闭。

CLR使用一种特殊的专用的线程来调用Finalize方法。

 

Finalization本质揭秘

当对象被创建的时候,系统会检测这些对象类型是否定义了Finalize方法,如果是,则将这些对象的指针添加到终结列表中。垃圾回收时,回收器会扫描终结列表以查找指向这些对象的指针,找到一个指针后,该指针会从终结列表中移除,并追加到f-reachable队列,这个f-reachable中的f代表终结,f-reachable队列中每个记录项所引用的对象都有Finalize方法,而且需要被调用。因此f-reachable队列中的对象不是垃圾。

简单的说,当一个对象不可达时。垃圾回收器把它当做垃圾,但是当垃圾回收器将对象引用从终结列表移到f-reachable队列时,对象不再被认为是垃圾,其内存不能被回收。由于一些原本被认为是垃圾的对象被重新认为不是垃圾,从某种意义上将,对象“复活”了。然后垃圾回收器开始回收,特殊的CLR线程会清空f-reachable队列,并且执行每个对象的finalize方法。

只有对象运行垃圾回收的时候,才会运行析构函数,析构函数最终肯定会运行,但是不能保证何时运行。

Finalize方法的问题在于,调用事件是不能保证的,它也不是公共方法,不能显式调用。

可以调用System.GC.Collect方法,从而在一个程序中调用垃圾回收器。然而,强烈建议不要这样做。System.GC.Collect将启动垃圾回收,但是这个回收过程是异步的。当方法结束时候,程序员仍然不知道对象是否被回收。

尽量避免使用析构函数,因为有析构函数的对象会被放置在f-reacheable队列中终结,所以会影响性能。

你可能感兴趣的:(职场,编译器,休闲)