在Java中将对象分配给null是否会影响垃圾收集?
在Java中将未使用的对象引用分配给null
是否以任何可衡量的方式改进垃圾回收过程?
我对Java(和C#)的使用经验告诉我,通常会违背虚拟机或JIT编译器,但我见过同事使用这种方法,我很好奇如果这是一个很好的做法或者其中一个巫术编程迷信?
通常,不。
但是像所有事情一样:这取决于。 现在Java中的GC非常好,所有的东西在不再可及之后都应该很快清理干净。 这是在离开一个局部variables的方法后,当一个类实例不再被引用的字段。
你只需要显式为null,如果你知道它将保持引用,否则。 例如一个数组,周围保持。 不再需要时,您可能需要将数组中的各个元素置零。
例如,来自ArrayList的这段代码:
public E remove(int index) { RangeCheck(index); modCount++; E oldValue = (E) elementData[index]; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
而且,只要没有引用保留,明确地将对象置为null也不会使对象被收集。
都:
void foo() { Object o = new Object(); /// do stuff with o }
和:
void foo() { Object o = new Object(); /// do stuff with o o = null; }
在function上是等同的。
根据我的经验,多数情况下,人们不是从偏执狂中脱离出来的,而不是出于必然。 这是一个快速的指导方针:
-
如果对象A引用了对象B, 并且不再需要此引用, 并且对象A不符合垃圾回收的条件,则应该明确地将该字段清空。 无论如何,如果封闭对象被垃圾收集,则不需要清空字段。 清空dispose()方法中的字段几乎总是没有用处。
-
没有必要清空方法中创build的对象引用。 一旦方法终止,它们将自动清除。 这个规则的例外是,如果你运行在一个非常长的方法或一个巨大的循环,你需要确保一些引用在方法结束之前被清除。 再次,这些案件是非常谨慎的。
我会说,绝大多数时候你不需要删除引用。 试图聪明的垃圾收集器是没用的。 你只会得到低效,不可读的代码。
至less在java中,根本不是巫术编程。 当你使用类似的东西在Java中创build一个对象
Foo bar = new Foo();
你做了两件事:首先,你创build一个对象的引用,其次,你自己创buildFoo对象。 只要该引用或其他引用存在,该特定对象就不能被引用。 但是,当您分配空引用…
bar = null ;
并假设没有任何其他对象具有引用,那么在垃圾回收器下一次通过时它将被释放并可用于gc。
明确地将引用设置为null,而不是让variables超出范围,这对垃圾回收器没有帮助,除非所持有的对象非常大,一旦完成就将其设置为null是个不错的主意。
通常将引用设置为null,意味着该对象的READER完全用完,并且不应该再担心。
通过join一些额外的括号可以达到类似的效果
{ int l; { String bigThing = ....; l = bigThing.length(); } --- }
这允许bigThing在离开嵌套括号后立即被垃圾收集。
这取决于。
一般来说,保持对象的引用越短,收集的速度越快。
如果你的方法需要2秒的执行时间,并且在方法执行一秒之后你不再需要一个对象,那么清除对它的引用是有意义的。 如果GC在一秒之后看到,你的对象仍然被引用,下一次它可能在一分钟左右检查它。
无论如何,默认情况下将所有引用设置为null对于我来说是不成熟的优化,除非在特定情况下显着减less内存消耗,否则任何人都不应该这样做。
public class JavaMemory { private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6); public void f() { { byte[] data = new byte[dataSize]; //data = null; } byte[] data2 = new byte[dataSize]; } public static void main(String[] args) { JavaMemory jmp = new JavaMemory(); jmp.f(); } }
上面的程序抛出OutOfMemoryError
。 如果取消注释data = null;
, OutOfMemoryError
被解决了。 将未使用的variables设置为null总是一个好习惯
好的文章是今天的编码恐怖 。
GC的工作方式是通过查找没有任何指针的对象,search区域是堆栈/堆栈以及其他任何空间。 所以如果你设置一个variables为null,实际的对象现在不被任何人指向,因此可能是GC'd。
但是由于GC可能不会在这个瞬间运行,所以你可能实际上并没有购买任何东西。 但是如果你的方法相当长(在执行时间方面),这可能是值得的,因为你将增加GC收集该对象的机会。
代码优化也可能会使问题变得复杂,如果您在将该variables设置为null之后从不使用variables,那么删除将值设置为null(仅执行一个指令)的行将是一个安全的优化。 所以你可能没有得到任何改善。
所以总而言之, 是的,它可以帮助,但它不会是确定性的 。
是。
从“实用程序员”p.292:
通过设置一个NULL的引用,你可以减less指向这个对象的指针的数量…(这将允许垃圾收集器删除它)
我曾经在一个video会议应用程序中工作,当我不再需要这个对象的时候,我花了很多时间来空引用,所以我注意到了巨大的性能差别。 这是在2003 – 2004年,我只能想象,GC已经变得更加聪明。 就我而言,我每秒钟都有数百个物体出现和超出范围,所以我注意到GC在周期性踢入时。 然而,在我将它指向空对象之后,GC停止暂停我的应用程序。
所以这取决于你在做什么…
我假设OP是指这样的事情:
private void Blah() { MyObj a; MyObj b; try { a = new MyObj(); b = new MyObj; // do real work } finally { a = null; b = null; } }
在这种情况下,不pipeVM在离开作用域后,VM是不会标记它们的?
或者从另一个angular度来看,明确地将这些项目设置为空,导致他们在超出范围之前就已经GC'd了? 如果是这样的话,当内存不再需要的时候,虚拟机可能会花费时间来处理对象,这实际上会导致更糟糕的性能CPU使用率,因为它会提前更快。
“ 这取决于 ”
我不知道Java,但在.net(C#,VB.net …)通常不需要分配一个空,当你不再需要一个对象。
但请注意,这通常是不需要的。
通过分析你的代码,.net编译器对variables的生命周期进行了很好的评估,以准确地判断对象何时不再被使用。 所以,如果你写obj = null,它实际上可能看起来好像仍在使用obj …在这种情况下,分配一个null是反效果的。
有几种情况可能实际上有助于分配空值。 一个例子是你有一个很长时间运行的巨大的代码或一个运行在不同的线程或一些循环的方法。 在这种情况下,可能有助于分配null,以便GC知道它不再被使用。
对此没有硬性规定。 去上面的地方空指派你的代码,并运行一个分析器,看看它是否有任何帮助。 很可能你可能没有看到好处。
如果是你想要优化的.net代码,那么我的经验是,使用Dispose和Finalize方法要比照顾空值更好。
有关该主题的一些参考资料
http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx
http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx
即使取消参考文件的效率稍微高一点点,那么丑陋的废除是否值得丑陋地代码呢? 他们只会混淆和掩盖包含它们的意图代码。
它是一个罕见的代码库,没有比试图超越垃圾收集器更好的候选人(更罕见的是仍然是成功地取代了成功的开发人员)。 你的努力很可能会更好地花在其他地方,抛弃那个蹩脚的XMLparsing器,或者find一些caching计算的机会。 这些优化将更容易量化,并且不要求您用噪声弄脏代码库。
在将来的程序执行中,一些数据成员的值将被用来计算在程序外部可见的输出。 其他可能会或可能不会被使用,取决于未来(而且不可能预测)input到程序中。 其他数据成员可能会被保证不被使用。 分配给这些未使用的数据的所有资源,包括内存都被浪费了。 垃圾收集器(GC)的工作是消除浪费的内存。 对于GC来说,消除所需的东西将是灾难性的,所以所使用的algorithm可能是保守的,保留超过严格的最小值。 它可能会使用启发式优化来提高其速度,但需要保留一些实际上不需要的项目。 GC可能使用许多潜在的algorithm。 因此,对程序所做的更改(不影响程序的正确性)可能会影响GC的运行,或者使其运行速度更快,以便执行相同的工作,或者尽早识别未使用的项目。 所以这种改变, 从理论上来说,设置一个无效的对象引用为null
,并不总是巫术。
是巫术吗? 据报道,这是Java库代码的一部分。 该代码的编写者比一般的程序员要好得多,要么知道,要么知道有谁知道垃圾收集器实现细节的程序员。 所以这表明有时候会有好处。