在 Java 中将对象分配给 null 会影响垃圾收集吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/449409/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:46:14  来源:igfitidea点击:

Does assigning objects to null in Java impact garbage collection?

javanullgarbage-collection

提问by James McMahon

Does assigning an unused object reference to nullin Java improve the garbage collection process in any measurable way?

null在 Java 中分配未使用的对象引用是否会以任何可衡量的方式改进垃圾收集过程?

My experience with Java (and C#) has taught me that is often counter intuitive to try and outsmart the virtual machine or JIT compiler, but I've seen co-workers use this method and I am curious if this is a good practice to pick up or one of those voodoo programming superstitions?

我在 Java(和 C#)方面的经验告诉我,尝试超越虚拟机或 JIT 编译器通常是违反直觉的,但我见过同事使用这种方法,我很好奇这是否是一个很好的选择up 还是那些巫毒编程迷信之一?

采纳答案by Mark Renouf

Typically, no.

通常,没有。

But like all things: it depends. The GC in Java these days is VERY good and everything should be cleaned up very shortly after it is no longer reachable. This is just after leaving a method for local variables, and when a class instance is no longer referenced for fields.

但就像所有事情一样:这取决于。现在 Java 中的 GC 非常好,所有东西都应该在不再可访问后很快被清理干净。这是在为局部变量留下一个方法之后,并且当一个类实例不再被字段引用时。

You only need to explicitly null if you know it would remain referenced otherwise. For example an array which is kept around. You may want to null the individual elements of the array when they are no longer needed.

如果您知道它会以其他方式保持引用,则只需要显式为 null。例如,一个保留在周围的数组。当不再需要数组的各个元素时,您可能希望将它们归零。

For example, this code from ArrayList:

例如,来自 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;
}

Also, explicitly nulling an object will not cause an object to be collected any sooner than if it just went out of scope naturally as long as no references remain.

此外,只要没有引用仍然存在,显式清空一个对象不会比它自然地超出范围时更早地导致对象被收集。

Both:

两个都:

void foo() {
   Object o = new Object();
   /// do stuff with o
}

and:

和:

void foo() {
   Object o = new Object();
   /// do stuff with o
   o = null;
}

Are functionally equivalent.

在功能上是等效的。

回答by James McMahon

Yes.

是的。

From "The Pragmatic Programmer" p.292:

来自“务实的程序员”p.292:

By setting a reference to NULL you reduce the number of pointers to the object by one ... (which will allow the garbage collector to remove it)

通过设置对 NULL 的引用,您可以将指向该对象的指针数量减少 1 ...(这将允许垃圾收集器将其删除)

回答by Charlie Martin

At least in java, it's not voodoo programming at all. When you create an object in java using something like

至少在 Java 中,它根本不是巫毒编程。当您使用类似的东西在 java 中创建对象时

Foo bar = new Foo();

you do two things: first, you create a reference to an object, and second, you create the Foo object itself. So long as that reference or another exists, the specific object can't be gc'd. however, when you assign null to that reference...

你做了两件事:首先,你创建了一个对象的引用,其次,你创建了 Foo 对象本身。只要该引用或其他引用存在,就无法对特定对象进行 gc'd。但是,当您将 null 分配给该引用时...

bar = null ;

and assuming nothing else has a reference to the object, it's freed and available for gc the next time the garbage collector passes by.

并假设没有其他对象引用该对象,它会在下次垃圾收集器经过时被释放并可供 gc 使用。

回答by earlNameless

Good article is today's coding horror.

好文章是今天的编码恐怖

The way GC's work is by looking for objects that do not have any pointers to them, the area of their search is heap/stack and any other spaces they have. So if you set a variable to null, the actual object is now not pointed by anyone, and hence could be GC'd.

GC 的工作方式是查找没有任何指向它们的指针的对象,它们的搜索区域是堆/堆栈以及它们拥有的任何其他空间。因此,如果您将变量设置为 null,则实际对象现在不会被任何人指向,因此可能会被 GC 处理。

But since the GC might not run at that exact instant, you might not actually be buying yourself anything. But if your method is fairly long (in terms of execution time) it might be worth it since you will be increasing your chances of GC collecting that object.

但是由于 GC 可能不会在那个确切的时刻运行,您实际上可能不会为自己购买任何东西。但是,如果您的方法相当长(就执行时间而言),那么它可能是值得的,因为您将增加 GC 收集该对象的机会。

The problem can also be complicated with code optimizations, if you never use the variable after you set it to null, it would be a safe optimization to remove the line that sets the value to null (one less instruction to execute). So you might not actually be getting any improvement.

该问题也可能因代码优化而变得复杂,如果在将变量设置为 null 后从不使用该变量,那么删除将值设置为 null 的行(少执行一条指令)将是一种安全的优化。所以你实际上可能没有得到任何改善。

So in summary, yes it can help, but it will not be deterministic.

所以总而言之,是的,它可以提供帮助,但它不会是确定性的

回答by Sesh

"It depends"

这取决于

I do not know about Java but in .net (C#, VB.net...) it is usually not required to assign a null when you no longer require a object.

我不了解 Java,但在 .net(C#、VB.net...)中,当您不再需要对象时,通常不需要分配 null。

However note that it is "usually not required".

但是请注意,它“通常不需要”。

By analyzing your code the .net compiler makes a good valuation of the life time of the variable...to accurately tell when the object is not being used anymore. So if you write obj=null it might actually look as if the obj is still being used...in this case it is counter productive to assign a null.

通过分析您的代码,.net 编译器对变量的生命周期进行了很好的评估……以准确判断何时不再使用对象。因此,如果您编写 obj=null,它实际上看起来好像仍在使用 obj ……在这种情况下,分配 null 会适得其反。

There are a few cases where it might actually help to assign a null. One example is you have a huge code that runs for long time or a method that is running in a different thread, or some loop. In such cases it might help to assign null so that it is easy for the GC to know its not being used anymore.

在某些情况下,它实际上可能有助于分配空值。一个例子是你有一个运行很长时间的巨大代码,或者一个在不同线程或某个循环中运行的方法。在这种情况下,分配 null 可能会有所帮助,以便 GC 很容易知道它不再被使用。

There is no hard & fast rule for this. Going by the above place null-assigns in your code and do run a profiler to see if it helps in any way. Most probably you might not see a benefit.

对此没有硬性规定。通过上面的地方在你的代码中分配空值,并运行一个分析器来看看它是否有任何帮助。您很可能看不到任何好处。

If it is .net code you are trying to optimize, then my experience has been that taking good care with Dispose and Finalize methods is actually more beneficial than bothering about nulls.

如果它是您要优化的 .net 代码,那么我的经验是,小心处理 Dispose 和 Finalize 方法实际上比担心空值更有益。

Some references on the topic:

关于该主题的一些参考资料:

http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx

http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx

http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx

http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx

回答by CodingWithSpike

I assume the OP is referring to things like this:

我认为 OP 指的是这样的事情:

private void Blah()
{
    MyObj a;
    MyObj b;

    try {
        a = new MyObj();
        b = new MyObj;

        // do real work
    } finally {
        a = null;
        b = null;
    }
}

In this case, wouldn't the VM mark them for GC as soon as they leave scope anyway?

在这种情况下,VM 不会在它们离开作用域后立即将它们标记为 GC 吗?

Or, from another perspective, would explicitly setting the items to null cause them to get GC'd before they would if they just went out of scope? If so, the VM may spend time GC'ing the object when the memory isn't needed anyway, which would actually cause worse performance CPU usage wise because it would be GC'ing more earlier.

或者,从另一个角度来看,是否将项目显式设置为 null 会导致它们在超出范围时先被 GC 处理?如果是这样,VM 可能会在不需要内存时花时间对对象进行 GC,这实际上会导致 CPU 使用率下降,因为它会更早地进行 GC。

回答by lubos hasko

It depends.

这取决于。

Generally speaking shorter you keep references to your objects, faster they'll get collected.

一般来说,您保留对对象的引用越短,收集它们的速度就越快。

If your method takes say 2 seconds to execute and you don't need an object anymore after one second of method execution, it makes sense to clear any references to it. If GC sees that after one second, your object is still referenced, next time it might check it in a minute or so.

如果您的方法需要 2 秒来执行,并且在方法执行一秒后您不再需要对象,则清除对它的任何引用是有意义的。如果 GC 在一秒钟后看到,你的对象仍然被引用,下次它可能会在一分钟左右检查它。

Anyway, setting all references to null by default is to me premature optimization and nobody should do it unless in specific rare cases where it measurably decreases memory consuption.

无论如何,默认情况下将所有引用设置为 null 对我来说是过早的优化,除非在特定的罕见情况下它显着减少内存消耗,否则没有人应该这样做。

回答by Gili

In my experience, more often than not, people null out references out of paranoia not out of necessity. Here is a quick guideline:

根据我的经验,人们常常出于偏执而不是出于必要而取消引用。这是一个快速指南:

  1. If object A references object B andyou no longer need this reference andobject A is not eligible for garbage collection then you should explicitly null out the field. There is no need to null out a field if the enclosing object is getting garbage collected anyway. Nulling out fields in a dispose() method is almost always useless.

  2. There is no need to null out object references created in a method. They will get cleared automatically once the method terminates. The exception to this rule is if you're running in a very long method or some massive loop and you need to ensure that some references get cleared before the end of the method. Again, these cases are extremely rare.

  1. 如果对象 A 引用了对象 B并且您不再需要此引用并且对象 A 不符合垃圾收集条件,那么您应该显式地将字段清空。如果封闭对象无论如何都被垃圾收集,则不需要将字段清空。在 dispose() 方法中清空字段几乎总是无用的。

  2. 不需要将方法中创建的对象引用归零。一旦方法终止,它们将被自动清除。此规则的例外情况是,如果您在一个很长的方法或某个大型循环中运行,并且您需要确保在方法结束之前清除某些引用。同样,这些情况极为罕见。

I would say that the vast majority of the time you will not need to null out references. Trying to outsmart the garbage collector is useless. You will just end up with inefficient, unreadable code.

我想说的是,绝大多数时候您不需要将引用归零。试图超越垃圾收集器是没有用的。你最终只会得到低效、不可读的代码。

回答by Thorbj?rn Ravn Andersen

Explicitly setting a reference to null instead of just letting the variable go out of scope, does not help the garbage collector, unless the object held is very large, where setting it to null as soon as you are done with is a good idea.

显式设置对 null 的引用而不是让变量超出范围,对垃圾收集器没有帮助,除非持有的对象非常大,一旦完成就将其设置为 null 是一个好主意。

Generally setting references to null, mean to the READER of the code that this object is completely done with and should not be concerned about any more.

一般将引用设置为null,意味着这个对象已经完全使用完的代码的READER,不需要再关心了。

A similar effect can be achieved by introducing a narrower scope by putting in an extra set of braces

通过添加一组额外的括号来引入更窄的范围,可以实现类似的效果

{
  int l;
  {  // <- here
    String bigThing = ....;
    l = bigThing.length();
  }  // <- and here
}

this allows the bigThing to be garbage collected right after leaving the nested braces.

这允许在离开嵌套大括号后立即对 bigThing 进行垃圾收集。

回答by Thorbj?rn Ravn Andersen

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();

    }

}

Above program throws OutOfMemoryError. If you uncomment data = null;, the OutOfMemoryErroris solved. It is always good practice to set the unused variable to null

上面的程序抛出OutOfMemoryError. 如果你取消注释data = null;OutOfMemoryError问题就解决了。将未使用的变量设置为 null 始终是一个好习惯