java - Java 可以检测何时可以显式释放对象吗?

标签 java

考虑以下 Java 类:

class Main
{
    private static Integer AddOne(Integer i) {
        return i + 1;
    }
    public static void main(String[] args)
    {
        Integer one = new Integer(1);
        System.out.println(AddOne(one));
    }
}

在这个简单的示例中,很容易看出,在调用 AddOne 后,one 引用的对象再也不会被引用。在 main 退出一段时间后,它将被垃圾回收。然而,将对象保留在内存中直到它被回收是一种浪费——对于Integer来说也许没有那么多,但如果我有一个大型数据结构(或其中许多),它可能会影响性能。

在我看来,编译器可以检查上面的代码,并发现对 one 的引用不可能转义 Main 类。然后,它可以在 main 函数末尾显式地释放/完成引用。

Java 实现中是否存在这样的功能?如果不是,是否有技术原因导致这种机制不起作用?

最佳答案

JIT Java 垃圾收集的最新进展使得此类问题的准确答案变得困难。但由于 language specification 的要求,JVM 必须支持一些功能。 .

特别是,即使字节码没有触及实例变量(例如未使用的私有(private)字段),JVM 也无法对它进行垃圾收集,因为调用者仍然可以使用反射来检查或访问该元素。

在您的示例中,我们讨论的是局部变量,它的处理方式不同。局部变量是在堆栈上分配的,而不是在堆上,并且一旦方法返回,垃圾收集器就可以毫无问题地清理它(实际上,甚至更快)。它不需要等到 Main 类被卸载。 one 引用的 Integer 对象会比 one 本身停留的时间更长,但一旦它未被引用,GC 就会在第一次机会。

我目前不知道这是否属实,但我想编译器甚至可以重新设计这样的代码以完全避免 Integer,并使用 int > 直接代替。本例中的 new 调用可能会显式阻止这种情况,但替换 Integer.valueOf() 会避免显式分配请求,并可能允许编译器避免在以下位置进行任何对象分配:全部。

当然,在这个简单的示例中,GC 或 JIT 不太可能有足够的时间来尝试清理任何内容。显然,您只是为了讨论而提供一个简单的示例,但值得一提的是,程序的持续时间会对 GC 或 JIT 的内容以及何时进行产生重大影响。

有可能使用 WeakReference 对其中的一些进行建模/测试,如果我有时间,我会尝试用一些示例代码/分析来重新审视这个答案。

您可能还会欣赏我去年提出的类似问题:Can unused private variables be GCed before their holding instance?

关于java - Java 可以检测何时可以显式释放对象吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26228239/

相关文章:

java - 如何在编译过程中捕获异常

java - Sikuli 无法通过 Jenkins 在屏幕上找到图像

java - 如何在 M1 MacBook 上使用 JavaFX?

Java - TestNG : Is It Wrong to use testng Assert. catch block 中的 fail()

java - 尝试在 Maven 发布准备和执行任务上运行并行构建时出现 Ger 错误?

java - 参数和参数

java - java中如何处理图像路径?

java.util.Function 或 Java 方法,哪一个是最佳实践?

java - 使用反射在 java 中为 android 转换对象

Java数组,随机数生成器+数组排序