Java/Object 的finalize() 方法是否与 C++ 的析构函数作用相同?

Java/Object 的finalize() 方法是否与 C++ 的析构函数作用相同?

Object 的finalize() 方法是否与 C++ 的析构函数作用相同?

  • 与 C++ 的析构函数不同,析构函数的调用时机是确定的,而 finalize() 方法的调用时机是不确定的
  • 当垃圾回收器要宣告一个对象死亡时,至少要经过两次标记。如果对象在进行可达性分析后,发现没有与 GC Roots 相连,就会被第一次标记,并且判断是否覆盖 finalize() 方法。如果对象覆盖了 finalize() 方法,并且没有与 GC Roots 相连,就会被放入 F-Qeueu 队列,并由稍后虚拟机建立的低优先级的 finalize 线程去执行触发 finalize 方法
  • 由于优先级比较低,finalize() 执行时可能随时被终止,不承诺等待其运行结束
  • finalize() 的作用是给予对象最后一次重生的机会
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Finalization {
private Finalization finalization;

@Override
protected void finalize() {
System.out.println("Finalized");
finalization = this;
}

public static void main(String[] args) {
Finalization f = new Finalization();
System.out.println("First print: " + f);
f = null;
System.gc();//调用垃圾回收,触发 finalize() 方法
System.out.println("Second print: " + f);
System.out.println(finalization);//虽然在 finalize() 中对 finalization 方法进行了重新赋值,但是 finalize() 方法在运行过程中可能会被提前终止,因此这里的 finalization 对象是 null。
}
}

上述代码的输出是:

1
2
3
4
First print: gc.Finalization@60e53b93
Second print: null
null
Finalized
最后一句代码System.out.println(finalization);的输出是 null,虽然在 finalize() 中对 finalization 方法进行了重新赋值,但是 finalize() 方法在运行过程中可能会被提前终止,因此这里的 finalization 对象是 null。 如果在System.gc();后让程序睡眠一段时间,则 finalize() 方法可以运行完成,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Finalization {
private static Finalization finalization;

@Override
protected void finalize() {
System.out.println("Finalized");
finalization = this;
}

public static void main(String[] args) {
Finalization f = new Finalization();
System.out.println("First print: " + f);
f = null;
System.gc();//调用垃圾回收,触发 finalize() 方法
try {
//这里睡眠 1 秒,让 GC 和 finalize() 方法有足够时间运行
Thread.currentThread().sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("Second print: " + f);
System.out.println(finalization);//这里的 finalization 的地址和 f 的地址是一样的
}
}
输出是:
1
2
3
4
First print: gc.Finalization@60e53b93
Finalized
Second print: null
gc.Finalization@60e53b93
重新赋值后,finalization 的地址和 f 的地址是一样的。但是由于 finalize() 方法运行时机的不确定性很大,且开销也很重,因此不推荐使用。

评论