是否将variable = null设置为垃圾回收

帮助我解决与同事的争议:在Java中设置一个variables或集合为null帮助垃圾收集并减less内存使用量? 如果我有一个长时间运行的程序,并且每个函数都可能被迭代调用(可能数千次):在将值返回给父函数之前,是否将其中的所有variables设置为null有助于减less堆大小/内存使用情况?

这是旧的表演绝杀。 这在1.0天内就是真的,但是编译器和JVM已经被改进以消除需求(如果有的话)。 如果您有兴趣,这篇优秀的IBM文章将深入细节: Java理论与实践:垃圾收集与性能

从文章:

有一种情况是使用显式调零不仅是有用的,而且实际上是需要的,也就是说,对一个对象的引用的范围比它被使用或被程序的规范认为是有效的范围更广。 这包括使用静态或实例字段来存储对临时缓冲区的引用(而不是本地variables),或者使用数组来存储可能保持运行时可访问的引用而不是程序的隐含语义的情况。

翻译:“显式为空”不再需要的持久对象。 (如果你想的话,“实际上需要”太强大的陈述?)

Java VM Spec

12.6.1实现最终化每个对象都可以用两个属性来表征:它可能是可达的,可达到的,或者不可达的,也可能是未定界的,可终结的或最终的。

可到达的对象是可以从任何活动的线程在任何潜在的继续计算中被访问的任何对象 。 可以devise优化程序的转换,以减less可达到的对象的数量,使其小于天真被认为可达的对象的数量。 例如,编译器或代码生成器可以select将不再使用的variables或参数设置为null,以使得这种对象的存储器可以更快地被回收。

讨论

如果对象字段中的值存储在寄存器中,则会发生另一个示例。 程序然后可以访问寄存器而不是对象,并且不再访问对象。 这意味着对象是垃圾。

如果可以参与任何潜在的继续计算,则该对象是可到达的。 所以,如果你的代码引用了一个局部variables,而没有别的东西引用它,那么你可能会通过设置它为null来收集对象。 这可能会给出一个空指针exception,或者改变你的程序的行为,或者如果它没有,你不需要在第一个variables。

如果您将某个字段或数组元素置为空,那么对于某些应用程序来说,这可能是有意义的,这会使内存更快地被回收。 一旦大小写创build一个大数组来replace一个类中的字段引用的现有数组 – 如果在replace之前的空字段被创build,那么它可以减轻对内存的压力。

Java的另一个有趣的特点是范围不会出现在类文件中,所以范围与可达性无关; 这两个方法创build相同的字节码,因此VM根本看不到所创build的对象的范围:

static void withBlock () { int x = 1; { Object a = new Object(); } System.out.println(x+1); } static void withoutBlock () { int x = 1; Object a = new Object(); System.out.println(x+1); } 

不必要。 当没有实时线程持有对该对象的引用时,对象变为符合垃圾回收的条件。

当方法返回时,局部variables超出范围,并且将局部variables设置为null是无意义的 – variables消失,如果没有任何其他variables引用了对象,那么这些对象变成有资格进行垃圾收集。

关键不在于查看variables,而是查看这些variables引用的对象,并找出程序引用的对象。

它在局部variables上是无用的,但是可以清除不再需要的实例variables(例如,后期初始化)。

(是啊,我知道如何应用Builder模式…)

这只能在这样的情况下有所帮助:

 public void myHeavyMethod() { List hugeList = loadHugeListOfStuff(); // lots of memory used ResultX res = processHugeList(hugeList); // compute some result or summary // hugeList = null; // we are done with hugeList ... // do a lot of other things that takes a LOT of time (seconds?) // and which do not require hugeList ... } 

在这里, 可以取消一些有利于取消注释hugeList = null行,我猜。

但是重写方法肯定会更有意义(也许重构为两个,或者指定一个内部范围)。

将对象引用设置为null仅适用于垃圾回收。 它不一定释放内存,这取决于垃圾收集器何时运行(取决于JVM)。 当垃圾收集器运行时,它通过删除仅适用于垃圾收集的对象来释放堆。

这是一件好事。 如果将对象设置为null,则可能会在即时GC循环中更快速地对对象进行垃圾回收。 但是在给定的时间内没有保证收集对象垃圾的机制。