我在浏览一些旧书时,发现了彼得·哈格(Peter Hagger)的“ Practical Java”的副本。在性能部分,建议null
不再使用对象引用。
在Java中,设置对象引用是否可以null
提高性能或垃圾回收效率?如果是这样,在什么情况下会出现问题?容器类?对象组成?匿名内部类?
我经常在代码中看到这一点。现在这是过时的编程建议还是仍然有用?
我在浏览一些旧书时,发现了彼得·哈格(Peter Hagger)的“ Practical Java”的副本。在性能部分,建议null
不再使用对象引用。
在Java中,设置对象引用是否可以null
提高性能或垃圾回收效率?如果是这样,在什么情况下会出现问题?容器类?对象组成?匿名内部类?
我经常在代码中看到这一点。现在这是过时的编程建议还是仍然有用?
Answers:
这取决于您何时考虑使引用无效。
如果您有一个对象链A-> B-> C,则一旦无法访问A,A,B和C都将有资格进行垃圾回收(假设其他任何东西都没有提及B或C)。例如,没有必要,也从来没有需要将引用A-> B或B-> C显式设置为null。
除此之外,大多数情况下并没有真正出现此问题,因为实际上您正在处理集合中的对象。通常,您应该始终考虑通过调用适当的remove()方法从列表,地图等中删除对象。
其中存在的情况下使用的是一些建议以空集的引用被具体地在长范围,其中一个存储器密集型对象不再是通过使用范围的中途。例如:
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; <-- explicitly set to null
doSomethingElse();
}
这里的理由是,因为obj仍在范围内,所以没有对引用进行显式的null删除,直到doSomethingElse()方法完成后,它才变得可垃圾回收。这是现代JVM上可能不再适用的建议:事实证明,JIT编译器可以在不再使用给定本地对象引用的情况下进行计算。
不,这不是过时的建议。悬挂引用仍然是一个问题,尤其是如果要ArrayList
使用预分配的数组实现可扩展数组容器(或类似对象)的话。超出列表“逻辑”大小的元素应被清空,否则它们将不会被释放。
请参阅有效的Java第二版,项目6:消除过时的对象引用。
实例字段,数组元素
如果存在对对象的引用,则无法对其进行垃圾回收。尤其是如果该对象(及其后面的整个图形)很大,则只有一个引用正在停止垃圾收集,并且不再需要该引用了,这是一种不幸的情况。
病理情况是对象保留了用于配置它的整个XML DOM树的非必需实例,未注销的MBean或未部署的Web应用程序中对对象的单个引用,从而阻止了整个类加载器的卸载。
因此,除非您确定拥有引用本身的对象无论如何都将被垃圾回收(或什至如此),否则您应该清空不再需要的所有内容。
范围变量:
如果您正在考虑将局部变量在其作用域结束之前设置为null,以便可以由垃圾收集器回收,并将其标记为“从现在开始不可用”,则应考虑将其置于更有限的作用域中。
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; // <-- explicitly set to null
doSomethingElse();
}
变成
{
{
BigObject obj = ...
doSomethingWith(obj);
} // <-- obj goes out of scope
doSomethingElse();
}
长而平坦的作用域通常也不利于代码的可读性。引入私有方法将其分解只是为了这个目的也是闻所未闻的。
首先,这并不意味着要将对象设置为null
。我在下面解释:
List list1 = new ArrayList();
List list2 = list1;
在上面的代码段中,我们正在创建存储在内存中list1
的ArrayList
对象的对象引用变量名称。list1
引用该对象也是如此,它不过是一个变量。而在第二行代码中,我们要复制的参考list1
来list2
。所以现在回到您的问题,如果我这样做:
list1 = null;
这意味着list1
不再引用存储在内存中的任何对象,因此list2
也就没有要引用的对象。因此,如果您检查的大小list2
:
list2.size(); //it gives you 0
因此,这里出现了垃圾收集器的概念,它表示“您不必担心释放对象所持有的内存,当我发现它将不再用在程序中并且JVM将管理我时,我将这样做。”
我希望它能弄清楚这个概念。