C#:应该将对象变量赋值为null吗?

时间:2010-10-11 06:22:28

标签: c# garbage-collection null

在C#中,如果您已经完成使用它,是否有必要将对象变量分配给null,即使它已经超出范围?

8 个答案:

答案 0 :(得分:38)

不,这实际上可能是危险的并且容易出错(考虑有人可能会在以后尝试使用它,而不是意识到它已被设置为null)。如果有逻辑原因将其设置为null,则仅将某些内容设置为null。

答案 1 :(得分:27)

更重要的是,IMO将对实现IDisposable的对象调用Dispose。

除此之外,为引用变量赋值null只意味着您明确指示范围结束 - 大多数时候,它只是早期的几条指令(例如,方法体中的局部变量) - 与编译器/ JIT的时代优化,很可能运行时会做同样的事情,所以你真的没有从中得到任何东西。在少数情况下,例如静态变量等(其范围是应用程序级别),如果使用完变量,则应将变量赋值为null,以便对象进行垃圾回收。

答案 2 :(得分:24)

在把车推到湖边之前,你应该把车关掉吗? 不。这是一个常见的错误,但它没有任何区别。您没有将对象设置为null,只有一个引用 - 对象仍然在内存中,并且仍然必须由垃圾收集器收集。

答案 3 :(得分:17)

这些答案中的大多数都有正确的答案,但出于错误的原因。

如果它是局部变量,则变量将在方法结束时从堆栈中掉落,因此它指向的对象将少一个引用。如果该变量是对象的唯一引用,则该对象可用于GC。

如果你将变量设置为null(并且许多人被教导在方法结束时这样做)那么你实际上可以最终延长对象留在内存中的时间,因为CLR会相信对象可以不会被收集到方法结束,因为它会看到对象的代码引用。但是,如果省略null设置,CLR可以确定在代码中的某个点之后不再显示对象,并且即使该方法尚未完成,GC也可以收集该对象。

答案 4 :(得分:11)

分配为null通常是一个坏主意:

  1. 从概念上讲,这是毫无意义的。
  2. 对于许多变量,您可以为null提供足够的额外赋值,以便明显增加方法的大小。某些东西的源代码越长,读取它的精力就越多(即使其中大部分只是可以过滤掉的东西)并且更容易发现错误。只有在这样做时才能使代码更加冗长,使其更容易理解。
  3. 您的空作业可能不会被优化掉。在这种情况下,编译的代码可能不会进行真正的释放,直到它实际到达那个空赋值,而在大多数情况下,一旦变量除了超出范围(有时甚至在之前)之外什么都不做可以解除分配。因此,您可以对性能产生非常小的影响。
  4. 我唯一一次将某些东西分配给null来“清除”一个不再使用的变量,而不是因为null实际上是一个我明确想要分配的值,这是两种可能的情况之一:

    1. 它是一个可能长寿命的对象的成员,将不再被该对象使用,并且具有相当大的尺寸。这里指定为null是一种优化。
    2. 它是一个可能长寿的对象的成员,将不再被该对象使用,因此被释放其资源。这里赋值为null是一个安全问题,因为它可以更容易找到一个意外使用空对象的情况,而不是一个意外使用被处置对象的情况。
    3. 这些情况都不适用于局部变量,只适用于成员,两者都很少见。

答案 5 :(得分:4)

没有。当谈到局部变量时,如果你有一个对象的引用,它就没有任何区别,重要的是如果使用或不使用引用。

在代码中添加一个额外的null赋值不会对性能造成太大影响,并且它根本不会影响内存管理,但它会将无动机的语句添加到代码中,使其可读性降低。

垃圾收集器知道代码中最后一次使用引用的时间,因此它可以在不再需要时立即收集该对象。

示例:

{
  // Create an object
  StringBuilder b = new StringBuilder();
  b.Append("asdf");
  // Here is the last use of the object:
  string x = b.ToString();
  // From this point the object can be collected whenever the GC feels like it
  // If you assign a null reference to the variable here is irrelevant
  b = null;
}

答案 6 :(得分:0)

我只想补充说AFAIK这只是Visual Basic的一个版本发布的有效模式,甚至 也有点争议。 (IIRC只适用于DAO对象。)

答案 7 :(得分:0)

对于必须实现IDisposable的对象,实际上,我将IDisposable实现中的所有成员设置为null。

在遥远的过去,我发现这种做法大大改善了Windows Mobile上运行的.NET Compact Framework应用程序的内存消耗和性能。我认为与主要的.NET Framework相比,当时的.NET Compact Framework可能具有非常简单的垃圾回收器实现,并且IDisposable实现中的对象解耦操作有助于.NET Compact Framework上的GC完成其工作

这种做法的另一个原因是在对象上执行了IDisposable之后,实际上不希望任何人尝试使用已处置对象上的任何成员。当然,理想情况下,您肯定希望从某个对象中获取ObjectDisposedException,该对象在某人尝试访问其任何功能时都已被处理,但是代替NullReferenceException总比没有异常好。您想了解代码将已处置的对象弄乱了,因为它们与已释放的非托管资源弄混了,这会使应用程序陷入很多麻烦。

注意:我绝对不主张出于将对象设置为null的其他原因而在对象上实现IDisposable。我说的是什么时候出于其他原因需要实现IDisposable,即您有实现IDisposable的成员或对象包装了非托管资源。