在finally块中是否有任何理由将对象设置为null ?

本文关键字:对象 设置 null 理由 任何 finally 是否 | 更新日期: 2023-09-27 18:12:24

我正在为我的公司清理一些c#代码,我一直注意到的一件事是,构建这个应用程序的承包商一直将对象引用设置为null。

的例子:

get {
  Object o = new Object(); // create a new object that is accessed by the reference 'o'
  try {
   // Do something with the object
  }
  finally {
    o = null; // set the reference to null
  }
}

据我所知,创建的对象仍然存在。有可能它现在不能被访问,这取决于是否有任何其他引用到它,但它仍然存在,直到GC来清理它。

有什么理由在finally块中有这个吗?是否有可能在某些情况下导致内存泄漏?

谢谢!

在finally块中是否有任何理由将对象设置为null ?

这取决于作用域。

在给定的示例中,o仅在属性范围内定义。所以它是没用的。但是,假设o在类的范围内。那么表示o的状态可能是有意义的。

如果目的是让GC尽快收集对象,那么它是完全无用的。

如果o引用的对象在try块之后没有在任何地方使用,它将在最后一次使用之后立即被选中进行收集(即在变量o超出作用域之前,在它到达finally块之前)。

相关说明,参见Lippert的构造破坏。

我认为这样做至少有两个原因。首先,始终如一地使用这种模式有助于捕获由重用变量引起的bug(例如,如果这是更大的代码序列的一部分,变量名'o'可能在稍后的执行中包含不同的对象)。通过显式地赋值null,您将确保这样的代码在稍后尝试使用相同对象时导致错误(假设您不小心注释掉了一个构造函数,作为更大块的一部分)。

其次,赋值null可以确保该对象可以被GC收集。虽然对类变量更重要,但即使是局部变量也可能受益。由于对象没有被赋值读取,任何现有的优化都不应该因为包含赋值而受到影响(尽管它可能是不必要的)。类似地,赋值本身可能会被完全优化(如果对象随后从未被访问),但由于这些优化都是编译器的权限,因此使用这种结构可以为不包括此类优化的备用编译模型提供早期收集的可能性。

需要比我更熟悉c#语言规范,但我怀疑它们没有规定对象必须在最后一次访问后立即分配用于收集。基于单个编译器或一组编译器的当前操作做出这种假设,可能会在以后尝试移植到不遵循相同原则的环境时导致更多的工作。

至于潜在的内存泄漏,假设GC工作正常,并且对象不需要特殊处理,应该没有问题——实际上,您是专门删除了对未使用内存的潜在引用,可能允许它被回收。对于有特殊处理要求的对象,我希望它们在同一个地方处理。