You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何重写的finalize()方法未被所有垃圾回收对象调用?

问题:触发GC后为何只有部分Tank对象的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()方法被执行,而非全部?

输出示例:

  1. 无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
  1. 仅出现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 15:15:57