显式归零

在什么情况下java中显式nulling有用。 它是否以任何方式通过使对象无法访问或某些东西来帮助垃圾收集器? 它被认为是一种好习惯吗?

在Java中,如果你有一个非常长时间运行的方法,它可以提供帮助,并且对对象的唯一引用是通过局部变量。 当您不再需要它时,将该局部变量设置为null(但是当该方法将继续运行很长时间时) 可以帮助GC。 (在C#中,这很少有用,因为GC会考虑“最后可能的用途”。这种优化可能会让它在Java中出现一段时间 – 我不知道。)

同样,如果您有一个成员字段引用一个对象而您不再需要它,则可以通过将该字段设置为null来帮助GC。

然而,根据我的经验,做这些事情中的任何一个都很少有用,而且会使代码变得更加混乱。 很少有方法真正运行很长时间,将变量设置为null实际上与您希望方法实现的内容无关。 当你不需要的时候这样做是不好的做法,如果你确实需要,你应该看看重构是否可以改善你的设计。 (你的方法或类型可能做得太多了。)

请注意,将变量设置为null完全是被动的 – 它不会通知垃圾收集器可以收集对象,它只是避免垃圾收集器将该引用视为下次保持对象存活的原因(GC)运行。

通常不需要(当然可以取决于VM实现)。 但是,如果您有这样的事情:

private static final Map foo; 

然后在地图中有不再需要的项目,它们将无法进行垃圾收集,因此您需要明确删除它们。 有很多这样的情况(事件监听器是另一个可能发生这种情况的领域)。

但做这样的事情:

 void foo() { Object o; // use o o = null; // don't bother doing this, it isn't going to help } 

编辑(忘了提这个):

如果您正在使用它,您会发现您声明的90-95%的变量可以是最终的。 最终变量不能改变它指向的内容(或者它的基元值是什么)。 在变量最终的大多数情况下,当方法执行时,它接收不同的值将是一个错误(错误)。

如果您希望能够在使用后将变量设置为null,则它不能是最终的,这意味着您有更大的机会在代码中创建错误。

我发现它有用的一个特例是当你有一个非常大的对象时,想要用另一个大对象替换它。 例如,查看以下代码:

 BigObject bigObject = new BigObject(); // ... bigObject = new BigObject(); // line 3 

如果BigObject的实例太大而你在堆中只能有一个这样的实例,那么第3行将因OutOfMemoryError而失败,因为在第3行的赋值指令完成之前,第1个实例无法释放,这显然是在第2个实例之后准备好了。

现在,如果您在第3行之前将bigObject设置为null:

 bigObject = null; bigObject = new BigObject(); // line 3 

在构建第二个实例期间,当JVM用完堆时,可以释放第一个实例。

从“Effective Java”:使用它来消除过时的对象引用。 否则会导致内存泄漏,这可能很难调试。

 public Object pop(){ if(size == 0) throw new EmptyStatckException(); Object result = elements[--size]; elements[size] = null; //Eliminate Object reference return result; } 

如果在方法块关闭时无论如何都要使一个即将超出范围的对象归零,那么在垃圾收集方面没有任何好处。 遇到那些不理解这一点的人并不罕见,他们很难将不必要的东西设置成很多东西。

另请参见J2SE中的WeakReference 。

在以下所有情况都属实的罕见情况下,显式归零可以帮助GC:

  • 变量是对象的唯一(非弱)引用
  • 您可以保证不再需要该对象
  • 变量将较长时间内保持在范围内(例如,它是长期对象实例中的字段)
  • 编译器无法certificate该对象不再使用,但您可以通过对代码的高级逻辑分析来保证这一点:-)

在实践中,这在很好的代码中是非常罕见的: 如果不再需要该对象,您通常应该在更窄的范围内声明它 。 例如,如果在方法的单个调用期间只需要对象,则它应该是局部变量,而不是封闭对象中的字段。

显式归零的一种情况确实很有用:如果使用null来表示特定状态,那么设置为空值有时是必要且有用的。 由于以下几个原因,Null本身是一个有用的值:

  • 空检查非常快,因此检查null的条件代码通常比许多替代方法更有效(例如,调用object.equals())
  • 如果您尝试取消引用它,则会立即获得NullPointerException。 这很有用,因为它是一种很好的Fail Fast编码风格,可以帮助您捕获逻辑错误。