内部类和垃圾收集:Java 8 和最新 Java 之间的行为差异

问题描述 投票:0回答:1

今天面试,面试官给出了如下代码。他们询问 Java 8 和最新版本的 Java 中的输出是什么。

根据我的理解,由于

B
是一个内部类(非静态嵌套类),它持有对
A
实例的引用,这可以防止
A
被垃圾收集(GC)。这种行为在 Java 8 中是预料之中的。然而,面试官演示了
A
可以在最新版本的 Java (Java 23) 中进行垃圾收集。然后他询问这个变化是在哪个版本的 Java 中发生的,以及为什么
A
现在可以被 GC 了。我相信这种行为要么与内部类的新机制有关(即使a
仍然存在,
b
也会被GC。原则上,
b
应该引用
a
)或新机制垃圾收集过程。然而我不知道答案。

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 java-8 jvm garbage-collection java-23
1个回答
0
投票

通过对Java 23以下各个版本进行实验,我发现这种现象是从Java 18开始的。然后我查阅了Java 18的新特性。

封闭不使用内部类中省略的实例字段 https://www.oracle.com/java/technologies/javase/18-relnote-issues.html#JDK-8271623

在 JDK 18 之前,当 javac 编译内部类时,它总是生成一个名称以 this$ 开头的私有合成字段,以保存对封闭实例的引用,即使内部类不引用其封闭实例和字段未使用。 从 JDK 18 开始,未使用的 this$ 字段被省略;该字段仅为引用其封闭实例的内部类生成。

© www.soinside.com 2019 - 2024. All rights reserved.