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

内部类与垃圾回收:Java 8与新版Java的行为差异及变更疑问

Java非静态内部类的GC行为版本差异问题

面试时遇到这样一个问题:面试官展示了一段Java代码,询问它在Java 8和最新版Java(Java 23)中的输出结果。按照以往的理解,非静态内部类B持有外部类A的实例引用,所以只要B还存活,A就无法被垃圾回收(GC),这也是Java 8中的实际表现。但面试官演示在Java 23中A可以被GC回收,随后问这个变更始于哪个Java版本,以及背后的原因。

测试代码

class A {
    class B {
        @Override
        protected void finalize() throws Throwable {
            System.out.println("B destroy");
        }
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("A destroy");
    }
}

public class Solution {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        A.B b = a.new B();
        a = null;
        System.gc();
        System.out.println("finish gc");
        Thread.sleep(1000);
        System.out.println("finish sleep");
    }
}

不同版本输出

Java 8输出

finish gc
finish sleep

Java 23输出

finish gc
A destroy
finish sleep

问题解答

  • 变更起始版本:该行为变更始于Java 16。
  • 原因解析:
    在Java 16之前,不管非静态内部类有没有实际用到外部类的成员(字段、方法),都会持有外部类实例的强引用——这就导致只要内部类实例还活着,外部类实例就永远不会被GC回收。
    从Java 16开始,编译器加入了针对性优化:如果非静态内部类完全没有访问外部类的任何成员,那么它对外部类实例的引用会被替换为弱引用。在这段测试代码里,B类只是重写了finalize方法,根本没用到A类的任何成员,所以B持有的是A的弱引用。当main方法把a置为null后,A实例就没有了任何强引用,GC就可以正常回收它,进而触发A destroy的输出。

内容的提问来源于stack exchange,提问作者maplemaple

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:54:51