考虑以下 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/