variable = null将其设置为垃圾回收

时间:2010-05-28 17:28:29

标签: java performance memory memory-management

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

8 个答案:

答案 0 :(得分:59)

这是旧表现的绝杀。这在1.0天内确实如此,但编译器和JVM已得到改进,以消除需求(如果有的话)。如果您感兴趣,这篇优秀的IBM文章会详细介绍:Java theory and practice: Garbage collection and performance

答案 1 :(得分:7)

来自文章:

  

有一种情况是使用显式归零不仅有用,而且实际上是必需的,并且这是对对象的引用范围比程序规范使用或认为有效的范围更广。这包括诸如使用静态或实例字段来存储对临时缓冲区的引用而不是本地变量的情况,或者使用数组来存储可以由运行时保持可访问而不是由程序的隐含语义可访问的引用。

翻译:“显式null”不再需要的持久对象。 (如果你愿意。“几乎要求”声明过于强烈?)

答案 2 :(得分:5)

Java VM Spec

  

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

     

可访问对象是任何可以从任何活动线程继续计算中访问的对象。可以设计优化程序的转换,以减少可达到的对象的数量,使其少于可以被认为可达的对象的数量。例如,编译器或代码生成器可以选择设置一个不再用于null的变量或参数,以使这种对象的存储可以更快地回收。

     

讨论

     

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

如果对象可以参与任何潜在的持续计算,则该对象是可达的。因此,如果您的代码引用了局部变量,并且没有其他内容引用它,那么您可以通过将其设置为null来使对象收集。这可能会给出一个空指针异常,或者改变程序的行为,或者如果它没有,你首先不需要变量。

如果要将字段或数组元素归零,那么对于某些应用程序来说这可能是有意义的,并且它将使内存更快地被回收。一旦case正在创建一个大型数组来替换类中某个字段引用的现有数组 - 如果创建了替换之前为空的字段,那么它可以减轻对内存的压力。

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

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

答案 3 :(得分:3)

不一定。当没有活动线程来保存对象的引用时,对象就有资格进行垃圾回收。

当方法返回时局部变量超出范围并且根本没有意义将局部变量设置为null - 变量无论如何都会消失,如果没有其他任何东西保存引用变量所引用的对象,那么这些对象有资格进行垃圾收集。

关键不是仅查看变量,而是查看这些变量引用的对象,并找出程序引用这些对象的位置。

答案 4 :(得分:2)

它对局部变量没有用处,但是它可能有用/需要清除不再需要的实例变量(例如,后期初始化)。

(是的,我知道如何应用Builder模式...)

答案 5 :(得分:1)

在某些情况下,这只能使某些有意义:

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行。

但重写方法肯定会更有意义(可能重构为两个, 或指定内部范围。)

答案 6 :(得分:0)

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

答案 7 :(得分:-4)

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