为何重写的finalize()方法未被所有垃圾回收对象调用?
我定义了一个Tank类,重写了finalize()方法:
@Override protected void finalize() { if (full) { // full 是boolean类型成员变量 System.out.println("Error: tank " + id + " must be empty at cleanup"); // id 是int类型成员变量 } else { System.out.println("Tank " + id + " cleaned up OK"); // id 是int类型成员变量 } }
随后创建了Tank类型数组并实例化每个元素,再通过循环将数组中所有引用置为null:
for (int i = 0; i < 5; i++) { tanks[i] = null; } System.gc();
每次运行程序,输出信息的组合都不同。我知道调用System.gc()不一定会触发垃圾回收,但疑惑的是:当垃圾回收确实被触发时,为什么只有部分“已死”对象的finalize()方法被执行,而非全部?
输出示例:
- 无Tank 0相关信息:
Tank 4 cleaned up OK Tank 3 cleaned up OK Error: tank 2 must be empty at cleanup Error: tank 1 must be empty at cleanup
- 仅出现Tank 4相关信息:
Tank 4 cleaned up OK
核心原因在于finalize()方法的执行机制和JVM垃圾回收的特性:
finalize()依赖低优先级独立线程执行:当JVM标记一个重写了
finalize()的对象为可回收时,会将它放入Finalizer队列,由专门的Finalizer线程处理该方法的执行。这个线程优先级很低,可能在它还没处理完队列中所有对象时,程序就已经终止,导致部分对象的finalize()完全没机会执行。GC的回收范围无强制保证:
System.gc()只是向JVM发起回收建议,JVM可根据当前内存状态选择只回收部分对象(比如优先清理新生代中占用空间大的对象,或内存压力较小时仅回收部分可回收对象)。未被本次GC选中的对象,自然不会触发finalize()。finalize()的执行无严格顺序与保障:JVM不承诺所有可回收对象的
finalize()都会被执行,也不保证执行顺序。哪怕对象已被标记为可回收,也可能因JVM调度策略、程序提前结束等原因,导致finalize()未被调用。
简单来说:你调用System.gc()后,JVM可能只回收了部分对象,再加上Finalizer线程的低优先级特性,没来得及处理所有待执行finalize()的对象,程序就结束了,所以每次输出内容都不一致。
内容的提问来源于stack exchange,提问作者KonstantinosTrimikliniotis

