对象复苏
当一个终止化对象被认为死亡时,垃圾收集器可以强制使该对象获得重生(进入终止化可达队列),因为这样才能调用对象的Finalize方法。在Finalize方法被调用之后,它才算真正的死亡了,一个终止化对象会经历死亡,重生然后再死亡的过程。该现象被称为复苏(resurrection)
- 垃圾收集器将对象的引用放到终止化可达队列,对象可达,获得了重生;
- 调用对象的Finalize方法后,再没有任何根指向对象,对象真正的死亡。
在对象的Finalize方法中将其指针再放入全局静态变量中,会怎么样??
namespace ResurrectionStudy
{
class Program
{
static void Main( string [] args)
{
SomeType s = new SomeType();
}
}
class SomeType
{
~ SomeType()
{
Console.WriteLine( " Finalize " );
MyApplication.objHandler = this ;
}
}
class MyApplication
{
public static object objHandler; // 默认为null
}
}
当执行Finalize时,该对象的一个引用将被放入一个根中,从而使其可达,对象重新复苏后垃圾收集器将不会认为其是可收集的垃圾。但是必须记住该对象已经被执行终止化了,使用可能会导致不可预期的结果。如果SomeType还引用了其他对象的字段的话,会使被引用的对象都重新复苏,但是这些重新复苏的对象中可能一些已经被执行了终止化。
一个不断复苏,永不死亡的对象。使用GC的ReRegisterForFinalize方法将指定对象添加到终止化链表的末端,会使对象的Finalize方法将再一次被调用。
namespace ResurrectionStudy
{
class Program
{
static void Main( string [] args)
{
SomeType s = new SomeType();
}
}
class SomeType
{
~ SomeType()
{
Console.WriteLine( " Finalize " );
MyApplication.objHandler = this ;
GC.ReRegisterForFinalize( this );
}
}
class MyApplication
{
public static object objHandler; // 默认为null
}
}
纯属娱乐,如果有需要可以在终止化方法内部根据一定的条件使对象重新复苏。
利用对象复苏设计一个对象池
对象复苏还是很有用的。假设创建一个Expensive对象池。由于对象非常耗费资源,创建他需要花费很多的时间,出于性能考虑,打算在应用程序启动之后就能创建一组Expensive对象,然后在应用程序整个生存期中重复地使用。
namespace ResurrectionStudy
{
class Expensive
{
static Stack pool = new Stack();
// 从对象池中获取对象
public static Expensive GetObjectFromPool()
{
return (Expensive)pool.Pop();
}
// 应用程序关闭时调用该方法,销毁对象池
public static void ShutdownThePool()
{
// 阻止终止化对象被加入对象池
pool = null ;
}
// 创建一个对象并将其添加到对象池中
public Expensive()
{
pool.Push( this );
}
// 当应用程序不再使用对象时,Finalize将会被调用
~ Expensive()
{
// 如果应用程序没有被关闭,将对象重新添加到对象池
if (pool != null )
{
// 调用ReRegisterForFinalize方法使对象以正确的状态加入到对象池
GC.ReRegisterForFinalize( this );
pool.Push( this );
}
}
}
}
当应用程序不再持有Expensive对象的引用,如果出现垃圾回收,那么Expensive将会被终止化。当Expensive对象的Finalize方法被调用后,它会将自己再次加入到对象池中,从而使其复苏,阻止垃圾收集器回收其内存。
当退出应用程序时,将pool字段设为null,当应用程序关闭时,CLR会为托管堆上的所有对象调用Finalize方法。因为这样子会导致无线循环(CLR会在40后强制中断进程)。如果pool为null,那么Expensive对象将不会再被添加到终止化链表上,同时也不会被添加到对象池中,Expensive的内存将会被回收。