在Java中将对象分配为null会影响垃圾回收吗?
在Java中将未使用的对象引用分配给null是否以任何可测量的方式改进了垃圾收集过程?
我使用Java(和C#)的经验告诉我,尝试和智能虚拟机或JIT编译器通常都是反直觉的,但我看到同事使用这种方法,我很好奇这是一个很好的选择 或者其中一个伏都教编程迷信?
13个解决方案
58 votes
通常,没有。
但就像所有事情一样:这取决于。 如今,Java中的GC非常好,所有内容都应该在不再可用后立即清理。 这就是在为局部变量留下一个方法之后,以及当不再为字段引用类实例时。
如果您知道它将继续引用,则只需要显式为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;
}
此外,只要没有引用仍然存在,显式地使对象无效就不会导致对象被收集得比它刚刚自然超出范围。
都:
void foo() {
Object o = new Object();
/// do stuff with o
}
和:
void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}
在功能上是等同的。
Mark Renouf answered 2019-05-06T04:16:51Z
10 votes
根据我的经验,人们往往忽略偏执狂的引用并非必要。 这是一个快速指南:
如果对象A引用对象B并且您不再需要此引用,并且对象A不符合垃圾回收条件,那么您应该明确地将该字段置空。 如果封闭对象无论如何都要收集垃圾,则无需将字段置空。 在dispose()方法中取消字段几乎总是无用的。
无需在方法中创建对象引用。 一旦方法终止,它们将自动清除。 此规则的例外情况是,如果您运行的是非常长的方法或某个大型循环,则需要确保在方法结束之前清除某些引用。 同样,这些案件极为罕见。
我会说绝大多数时候你不需要废除引用。 试图超越垃圾收集器是没用的。 您将最终得到效率低下,难以理解的代码。
Gili answered 2019-05-06T04:17:36Z
7 votes
好文章是今天的编码恐怖。
GC的工作方式是查找没有任何指针的对象,搜索区域是堆/堆栈以及它们拥有的任何其他空间。 因此,如果将变量设置为null,则实际对象现在不会被任何人指向,因此可能是GC'd。
但由于GC可能不会在那个确切的瞬间运行,你可能实际上并没有自己购买任何东西。 但是如果你的方法相当长(就执行时间而言)可能是值得的,因为你将增加GC收集该对象的机会。
代码优化也会使问题变得复杂,如果在将变量设置为null后从不使用变量,则删除将值设置为null的行是一种安全的优化(少执行一条指令)。 所以你可能实际上没有得到任何改进。
总而言之,是的它可以提供帮助,但它不具有确定性。
earlNameless answered 2019-05-06T04:18:30Z
6 votes
至少在java中,它根本不是巫毒编程。 使用类似的东西在java中创建对象时
Foo bar = new Foo();
你做两件事:首先,你创建一个对象的引用,第二,你创建Foo对象本身。 只要该引用或其他引用存在,特定对象就不能被gc'd。 但是,当您为该引用赋值null时...
bar = null ;
并假设没有其他任何东西有对该对象的引用,它在下次垃圾收集器经过时被释放并可用于gc。
Charlie Martin answered 2019-05-06T04:19:08Z
5 votes
这取决于。
一般来说,你保持对物体的引用越短,它们就越快被收集。
如果您的方法需要2秒钟才能执行,并且在方法执行一秒后不再需要对象,则清除对它的任何引用都是有意义的。 如果GC在一秒钟后看到,您的对象仍然被引用,下次它可能会在一分钟左右检查它。
无论如何,默认情况下将所有引用设置为null对我来说是过早优化,没有人应该这样做,除非在特定的罕见情况下它可以显着减少内存消耗。
lubos hasko answered 2019-05-06T04:19:49Z
5 votes
显式设置对null的引用而不是仅让变量超出范围,对垃圾收集器没有帮助,除非持有的对象非常大,一旦完成就将其设置为null是一个好主意。
通常将引用设置为null,意味着该对象完全使用的代码的READER,并且不应再关注它。
通过添加一组额外的支架可以实现类似的效果
{
int l;
{
String bigThing = ....;
l = bigThing.length();
}
---
}
这允许bigThing在离开嵌套大括号后立即进行垃圾收集。
Thorbjørn Ravn Andersen answered 2019-05-06T04:20:35Z
5 votes
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。 将未使用的变量设置为null始终是一种好习惯
omiel answered 2019-05-06T04:21:00Z
3 votes
我曾经在视频会议应用程序上工作过一次,当我不再需要该对象时,我花时间将引用归零时,发现性能上有巨大的巨大差异。 这是在2003-2004,我只能想象GC从那时起变得更加聪明。 在我的情况下,我每秒都有数百个物体进出范围,所以我注意到GC定期开始运行。 然而,在我指出null对象后,GC停止了暂停我的应用程序。
所以这取决于你在做什么......
Perry answered 2019-05-06T04:21:33Z
2 votes
是。
来自“务实的程序员”第292页:
通过设置NULL引用,您可以将对象的指针数减少一个...(这将允许垃圾收集器将其删除)
answered 2019-05-06T04:22:08Z
1 votes
我假设OP指的是这样的事情:
private void Blah()
{
MyObj a;
MyObj b;
try {
a = new MyObj();
b = new MyObj;
// do real work
} finally {
a = null;
b = null;
}
}
在这种情况下,VM一旦离开范围,就不会为GC标记它们吗?
或者,从另一个角度来看,将项显式设置为null会导致它们在它们刚刚超出范围之前得到GC吗? 如果是这样,当无论如何不需要内存时,VM可能花费时间对对象进行GC操作,这实际上会导致性能更差的CPU使用,因为它会更早地进行GC。
CodingWithSpike answered 2019-05-06T04:22:47Z
0 votes
“这取决于”
我不知道Java,但在.net(C#,VB.net ......)中,当你不再需要一个对象时,通常不需要指定null。
但请注意,“通常不需要”。
通过分析您的代码,.net编译器可以很好地估计变量的生命周期......以准确地判断对象何时不再使用。 因此,如果你编写obj = null,它实际上看起来好像obj仍然被使用...在这种情况下,分配null是有效的。
在某些情况下,实际上可能有助于分配null。 一个例子是你有一个很长时间运行的庞大代码或一个在不同线程或某个循环中运行的方法。 在这种情况下,可能有助于分配null,以便GC很容易知道它不再被使用。
没有硬& 快速的规则。 按上述位置进行null分配代码并运行分析器以查看它是否有任何帮助。 很可能你可能没有看到任何好处。
如果是.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]
Sesh answered 2019-05-06T04:24:14Z
0 votes
即使取消参考文件的效率稍微提高一点,是否值得用这些丑陋的无效方法来编写代码? 它们只会混乱并且模糊包含它们的意图代码。
它是一个罕见的代码库,没有更好的优化候选者,而不是试图超越垃圾收集器(更罕见的仍然是成功超越它的开发人员)。 你的努力很可能会更好地花在其他地方,放弃那个狡猾的Xml解析器或找到一些缓存计算的机会。 这些优化将更容易量化,并且不要求您使用噪声污染代码库。
sgargan answered 2019-05-06T04:24:46Z
0 votes
在将来执行程序时,某些数据成员的值将用于计算程序外部可见的输出。根据未来(并且无法预测)对计划的输入,可能会或可能不会使用其他人。可能保证不使用其他数据成员。分配给这些未使用数据的所有资源(包括内存)都被浪费了。垃圾收集器(GC)的工作是消除浪费的内存。 GC消除所需的东西将是灾难性的,因此使用的算法可能是保守的,保留超过严格的最小值。它可能会使用启发式优化来提高其速度,但代价是保留一些实际上不需要的项目。 GC可能会使用许多潜在的算法。因此,您对程序所做的更改以及不影响程序正确性的更改可能会影响GC的运行,或者使其运行速度更快以执行相同的工作,或者更快地识别未使用的项目。所以这种改变,设置一个不对称的对象参考null,理论上并不总是伏都教。
是伏都教吗? 据报道,部分Java库代码可以执行此操作。 该代码的编写者比普通程序员好得多,他们知道或者与了解垃圾收集器实现细节的程序员合作。 这表明有时会带来好处。
Raedwald answered 2019-05-06T04:25:21Z