将 Java 对象设置为 null 还有用吗?

我在浏览一些旧书时发现了一本彼得 · 哈格尔的《实用爪哇》。在性能部分,建议在不再需要时将对象引用设置为 null

In Java, does setting object references to null improve performance or garbage collection efficiency? If so, in what cases is this an issue? Container classes? Object composition? Anonymous inner classes?

我经常在代码中看到这种情况。这是现在已经过时的编程建议,还是仍然有用?

63160 次浏览

不,这不是过时的建议。悬空引用仍然是一个问题,特别是如果您正在使用预分配的数组实现可扩展数组容器(ArrayList或类似的)。超出列表“逻辑”大小的元素应该为空,否则它们将不会被释放。

请参阅有效的 Java2nd ed,第6项: 消除过时的对象引用。

在内存受限的环境(例如手机)中,这是很有用的。通过设置 null,objecetc 不需要等待变量超出作用域才能被 gc 化。

然而,对于日常编程来说,这不应该成为规则,除非是像 Chris Jester-Young 引用的那种特殊情况。

It depends a bit on when you were thinking of nulling the reference.

如果您有一个对象链 A-> B-> C,那么一旦 A 不可访问,A、 B 和 C 都将有资格进行垃圾收集(假设没有其他任何对象引用 B 或 C)。例如,没有必要,也从来没有必要显式地将引用 A-> B 或 B-> C 设置为 null。

除此之外,大多数时候这个问题并没有真正出现,因为实际上您处理的是集合中的对象。通常情况下,您应该考虑通过调用适当的 move ()方法从列表、映射等中删除对象。

不再在作用域中使用内存密集型对象的长作用域中,曾经是有一些将引用设置为 null 的建议。例如:

{
BigObject obj = ...
doSomethingWith(obj);
obj = null;             <-- explicitly set to null
doSomethingElse();
}

这里的基本原理是,因为 obj仍然在作用域中,所以如果没有引用的显式空值,那么在 doSomethingElse()方法完成之前它不会成为垃圾收集器。这就是 可能不再适用于现代 JVM的建议: JIT 编译器可以计算出在什么时候不再使用给定的本地对象引用。

Instance fields, array elements

如果存在对对象的引用,则不能对其进行垃圾回收。特别是如果该对象(及其后面的整个图)很大,那么只有一个引用停止垃圾收集,并且不再真正需要该引用,这是一种不幸的情况。

Pathological cases are the object that retains an unnessary instance to the whole XML DOM tree that was used to configure it, the MBean that was not unregistered, or the single reference to an object from an undeployed web application that prevents a whole classloader from being unloaded.

因此,除非您确信保存引用本身的对象将被垃圾收集(或者即便如此) ,否则应该清除不再需要的所有内容。

作用域变量:

如果您正在考虑在局部变量的作用域结束之前将其设置为 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;

在上面的代码段中,我们创建了存储在内存中的 ArrayList对象的对象引用变量名 list1。所以 list1引用的是那个对象它只不过是一个变量。在第二行代码中,我们将 list1的引用复制到 list2。所以现在回到你的问题,如果我这样做:

list1 = null;

这意味着 list1不再引用存储在内存中的任何对象,因此 list2也将没有任何可引用的对象。所以如果你检查 list2的大小:

list2.size(); //it gives you 0

所以这里垃圾收集器的概念出现了,也就是 «you nothing to worry about freeing the memory that is hold by the object, I will do that when I find that it will no longer used in program and JVM will manage me.»

我希望你能理清思路。

这样做的原因之一是为了消除过时的对象引用。 你可以在这里阅读文本 < a href = “ http://www.Informit.com/article/article/artile.aspx? p = 1216151 & amp; seqNum = 6”rel = “ nofollow noReferrer”> 。