在 finally 块中将一个对象设置为 null 有什么理由吗?

9

我正在为我的公司整理一些 C# 代码,发现承包商在构建此应用程序时经常将对象引用设置为空。

示例:

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

据我所知,创建的对象仍然存在。如果有其他引用,那么现在可能无法访问它,但直到垃圾回收程序清理它之前,它仍将存在。
把这段代码放在finally块中是否有任何原因?是否存在可能会意外导致内存泄漏的情况?
谢谢!

3
听起来像是那些没有学习过.NET内存管理与VB的COM管理有所不同的Ex VB(经典版)程序员。 - Damien_The_Unbeliever
我想这是一种很好的处理方式。 - Matias Cicero
1
@MatiCicero:不是的。这是典型的“船只崇拜编程”,表明缺乏理解。 - Michael Borgwardt
3个回答

16

这取决于作用域。

在您给出的示例中,o仅在属性作用域内定义,因此它将是无用的。 但是,假设o在类的范围内,则可能有意义指示o的状态。

目前情况下,这是不必要的。


但是创建的对象仍然会占用内存,对吗?只是将对象的引用设置为null。垃圾回收器不知道何时最后使用对象,因此不需要通过显式设置所有引用为null来告诉它。 - CodyEngel
如果引用仍在范围内,它们应该被设置为null,这样GC就知道它们不再使用了。 - Russell at ISC
@Russell,啊哈,我以为垃圾回收机制的工作方式不一样。 - CodyEngel

6
如果意图是让GC尽快收集对象,那么这样做完全没有用处。
如果由o引用的对象在try块之后没有被任何地方使用,那么它将在最后一次使用后立即被选中进行回收(即在变量o超出范围和到达finally块之前)。
相关内容请参见Lippert的Construction Destruction

2
+1 附上 Eric Lippert 文章的链接。重要的是要知道,在 C# 中,“作用域”的概念与花括号的嵌套几乎没有任何关系。 - OldFart

0

我认为有至少两个原因这样做。首先,始终使用此模式有助于捕获由重用变量引起的错误(例如,如果这是代码序列的一部分,则变量名“o”可能在执行后期保留不同的对象)。通过明确地赋值为null,您将确保如果您稍后尝试使用相同的对象(比如您意外注释掉了一个构造函数作为较大块的一部分),则此类代码会导致错误。

其次,赋值为null确保对象可能可供GC收集。虽然对于类变量更为重要,但即使局部变量也可能受益。由于该对象未被读取,因此任何现有的优化都不应受到包括该赋值(无论多么不必要)的影响。同样,该赋值本身可能会被完全优化掉(如果从未随后访问该对象),但由于这些优化都是编译器的职责范围,因此使用此结构允许早期收集的可能性,以用于不包括此类优化的备选编译模型。

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

至于潜在的内存泄漏,假设GC正常工作,并且对象不需要特殊处理,那么就不应该有问题-实际上,您正在明确删除对未使用内存的潜在引用,可能允许其被回收。对于具有特殊处理要求的对象,我希望它们在同一位置处理。


我不知道你在说什么,因为这只是一堵文字墙。你可能需要考虑将答案的不同部分分成段落。 - Damien_The_Unbeliever

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接