【发布时间】:2011-04-23 15:56:26
【问题描述】:
在 C# 中,是否有必要将一个对象变量分配给 null,如果你已经使用它,即使它会超出范围?
【问题讨论】:
标签: c# garbage-collection null
在 C# 中,是否有必要将一个对象变量分配给 null,如果你已经使用它,即使它会超出范围?
【问题讨论】:
标签: c# garbage-collection null
不,这实际上可能很危险且容易出错(考虑到有人可能稍后尝试使用它,而没有意识到它已被设置为 null)。仅当有合理的理由将其设置为 null 时才将其设置为 null。
【讨论】:
IMO 更重要的是在实现 IDisposable 的对象上调用 Dispose。
除此之外,将 null 分配给引用变量仅意味着您明确指示范围的结束 - 大多数情况下,它只是早期的几条指令(例如,方法体中的局部变量) - 在编译器/JIT 时代优化,运行时很可能会做同样的事情,所以你真的没有得到任何东西。在少数情况下,例如静态变量等(其范围是应用程序级别),如果您使用完变量,则应该将变量分配给 null,以便对象被垃圾收集。
【讨论】:
在把车推到湖边之前,你应该把车熄火吗?
不,这是一个常见的错误,但没有任何区别。您没有将 object 设置为 null,只是对它的一个 reference - 该对象仍在内存中,并且仍必须由垃圾收集器收集。
【讨论】:
这些回答中的大多数都有正确的答案,但原因却是错误的。
如果它是一个局部变量,该变量将在方法结束时从堆栈中掉下来,因此它指向的对象将少一个引用。如果该变量是对该对象的唯一引用,则该对象可用于 GC。
如果您将变量设置为 null(并且许多人在方法结束时被教导这样做),那么您实际上可能会延长对象在内存中的停留时间,因为 CLR 会相信该对象可以'直到方法结束才被收集,因为它在那里看到了对对象的代码引用。但是,如果您忽略 null 的设置,CLR 可以确定在您的代码中的某个点之后不再出现对该对象的调用,即使该方法尚未完成,GC 也可以收集该对象。
【讨论】:
分配给 null 通常是个坏主意:
我唯一一次将某些东西分配给 null 以“清除”一个将不再使用的变量,而不是因为 null 实际上是我明确想要分配的值,这是两种可能的情况之一:
这两种情况都不适用于局部变量,只适用于成员,而且都很少见。
【讨论】:
没有。当涉及到局部变量时,如果您对对象有引用,则根本没有区别,重要的是是否会使用该引用。
在代码中添加一个额外的 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;
}
【讨论】:
对于必须实现 IDisposable 的对象,作为一种做法,我在 IDisposable 的实现中将所有成员设置为 null。
在很久以前,我发现这种做法极大地改善了在 Windows Mobile 上运行的 .NET Compact Framework 应用程序的内存消耗和性能。我认为与主要的 .NET Framework 相比,当时的 .NET Compact Framework 可能有一个非常简约的垃圾收集器实现,并且在 IDisposable 的实现中解耦对象的行为帮助 .NET Compact Framework 上的 GC 完成了它的工作.
这种做法的另一个原因是在对对象执行 IDisposable 之后,实际上不希望任何尝试使用已处置对象上的任何成员。当然,理想情况下,您希望在某个对象尝试访问其任何功能时从已处置的对象中取出 ObjectDisposedException,但取而代之的是 NullReferenceException 总比没有异常好。您想知道代码会弄乱已释放的对象,因为玩弄已释放的非托管资源会给应用程序带来很多麻烦。
注意:我绝对不提倡在对象上实现 IDisposable,除了将成员设置为 null 之外没有其他原因。我说的是当您出于其他原因需要实现 IDisposable 时,即您有实现 IDisposable 的成员或您的对象包装了非托管资源。
【讨论】:
我想补充一点,AFAIK 这只是 Visual Basic 单点版本的有效模式,甚至 也有一些争议。 (IIRC 仅适用于 DAO 对象。)
【讨论】: