JVM - 一次对象的自我拯救过程

故事:

在噼里啪啦星球,有这样一个原始部落,该部落民风淳朴。但也是有着严厉的法令去约束他们的行为。比如法令中有这样一条:死刑。考虑到该刑法过于严重,所以该法令有个特权,缓刑执行,允许犯人缓刑执行期间自救,但是自救的行为每个人一生只有一次。假如某个人已经使用过自救的特权,那么再次被判了死刑的话会被立即处决。初犯死刑的人员如果在自救期间能够找到证据证明自己的清白,那么他就会被豁免死刑,从而继续存活,如果没找到还是会被执行死刑。(该故事由《深入Java虚拟机》章节3.2.4 “缓刑”一词联想而来,契合了一次对象的自我拯救过程,所以拿来作为引子,但也有些区别,这里还请读者自行理解,如有不当还请指出)

在经过可达性分析算法判定某个对象为不可达时(犯了死刑),该对象也并非是“非死不可”的,这时候他们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经过两次标记的过程(缓刑):如果对象在进行可达性分析后发现没有与GC Roots 相连接的引用链,那他会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法(这里检查是否已使用过自救的特权)。当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用过(没有自救的特权必死。喝了这碗酒,你安心上路,你老婆我来照顾→_→),虚拟机将这两种情况都视为“没有必要执行”。

如果这个对象被判定有必要执行finalize()方法时(初犯死刑,还有自救特权),那么对将这个对象放置在一个叫做F-Queue的队列中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()方法中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可(找到证据证明自己的清白)。这样第二次标记时,他将被移除“即将回收”的集合(本次豁免死刑)。如果对象此时还没有逃脱那基本上他就被真的回收了(未找到证据证明自己的清白,安心上路,你老婆我来照顾→_→)。

书中代码示例,这里直接粘过来的

/**
 * 此代码演示了两点: 1. 对象可以在被 GC 时自我拯救 
 * 2. 这种自救的机会只有一次,因为一个对象的finalize()方法只会被系统自动调用一次
 * 
 * @author cyl
 */
public class FinalizeEscapeGC {

	public static FinalizeEscapeGC SAVE_HOOK = null;

	public void isAlive() {
		System.out.println("yes, i am still alive :)");
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("finalize method executed!");
		FinalizeEscapeGC.SAVE_HOOK = this;
	}

	public static void main(String[] args) throws InterruptedException {
		SAVE_HOOK = new FinalizeEscapeGC();

		// 对象第一次成功拯救自己
		SAVE_HOOK = null;
		System.gc();
		// 因为 finalize 优先级很低,所以暂停 0.5 秒等待他
		Thread.sleep(500);
		if (SAVE_HOOK != null) {
			SAVE_HOOK.isAlive();
		} else {
			System.out.println("yes, i am still alive :(");
		}
		/***************************************/
		// 下面的代码与上面的完全相同,但是这次自救却失败了
		SAVE_HOOK = null;
		System.gc();
		// 因为 finalize 优先级很低,所以暂停 0.5 秒等待他
		Thread.sleep(500);
		if (SAVE_HOOK != null) {
			SAVE_HOOK.isAlive();
		} else {
			System.out.println("no, i am dead :(");
		}
	}

}
/**运行结果
 * finalize method executed!
 * yes, i am still alive :)
 * no, i am dead :(
 */

PS:任何一个对象的finalize()方法只会被系统自动调用一次。

猜你喜欢

转载自blog.csdn.net/qq_29676623/article/details/84172709