Java variable=null是否将其设置为垃圾收集

Java variable=null是否将其设置为垃圾收集,java,performance,memory,memory-management,Java,Performance,Memory,Memory Management,帮助我解决与同事的纠纷: 在Java中将变量或集合设置为null是否有助于垃圾收集和减少内存使用?如果我有一个长时间运行的程序,并且每个函数都可能被迭代调用(可能是数千次):在将值返回给父函数之前,是否将其中的所有变量设置为null有助于减少堆大小/内存使用量?不一定。当不再有活动线程持有对对象的引用时,对象就有资格进行垃圾收集 当方法返回时,局部变量超出范围,将局部变量设置为null毫无意义-无论如何,这些变量都会消失,如果没有其他东西保存变量引用的对象的引用,那么这些对象就有资格进行垃圾收集

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

不一定。当不再有活动线程持有对对象的引用时,对象就有资格进行垃圾收集

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


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

这是旧的性能知识。这在1.0时代是正确的,但是编译器和JVM已经得到了改进,以消除这种需要(如果有)。如果您感兴趣,这篇优秀的IBM文章将详细介绍:

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


(是的,是的,我知道如何应用生成器模式…

这是一个很好的选择。当您将objects设置为null时,有可能在即时GC循环中更快地对该对象进行垃圾收集。但是,没有保证在给定时间对对象进行垃圾收集的机制。

Java VM规范

12.6.1实施最终定稿 每个对象都可以由两个属性描述:它可以是可访问的、终结器可访问的或不可访问的,也可以是未终结的、可终结的或终结的

可访问对象是可以从任何活动线程在任何可能的连续计算中访问的任何对象。可以设计程序的优化转换,以减少可访问对象的数量,使其少于天真地认为可访问的对象的数量。例如,编译器或代码生成器可能会选择将不再使用的变量或参数设置为null,以使此类对象的存储可能更快地被回收

讨论

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

如果对象可以参与任何潜在的连续计算,则该对象是可到达的。因此,如果您的代码引用了一个局部变量,而没有其他东西引用它,那么您可能会通过将其设置为null来收集该对象。这可能会产生一个空指针异常,或者改变程序的行为,或者如果两者都没有,那么您首先就不需要变量

如果将字段或数组元素置零,则这可能对某些应用程序有意义,并且会导致更快地回收内存。一旦case创建了一个大数组来替换类中某个字段引用的现有数组-如果在创建替换之前该字段已为null,则可能会减轻内存压力

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);
}
只有在这样的情况下,这才有意义:

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)。
当垃圾收集器运行时,它只删除符合垃圾收集条件的对象来释放堆。

仅当VM未实现JVM规范的版本3时。请阅读我回答中关于可达性的引文。如果processHughList没有存储对hugeList引用的对象的引用,那么它就不能“在任何活动线程的任何潜在连续计算中访问”,因此是不可访问的,因此有资格进行垃圾收集。如果processHughList只使用大小和数据数组(假设List类似于ArrayList),并且这些数组被JITted为寄存器变量,然后,甚至可以在processHughList返回之前收集该对象。只有在代码非常复杂的情况下,编译器/jit才能看到调用processHugeList后没有使用hugeList。在某些特殊情况下,这可能是一个好主意,但您肯定不应该总是将变量设置为
null
(请注意,准确一点很重要:你不能”