在.NET中使用后将对象设置为Null / Nothing

c# .net vb.net memory memory-management

79840 观看

14回复

18950 作者的声誉

完成后,是否应该将所有对象设置为nullNothing在VB.NET中)?

我理解在.NET中必须处理实现IDisposable接口的任何对象实例以释放一些资源,尽管对象在处理之后仍然可以是某种东西(因此isDisposed表单中的属性),所以我认为它仍然可以驻留在记忆中还是至少部分?

我也知道当一个对象超出范围时,它会被标记为收集准备好下一次垃圾收集器的传递(虽然这可能需要时间)。

因此,考虑到这一点,将其设置为null加速系统释放内存,因为它不必解决它不再在范围内并且它们是否有任何不良副作用?

MSDN文章从未在示例中执行此操作,目前我这样做是因为我无法看到它的危害。但是我遇到了各种意见,所以任何评论都是有用的。

作者: John 的来源 发布者: 2008 年 8 月 5 日

回应 14


-1

34996 作者的声誉

某些对象假设.dispose()强制从内存中删除资源的方法。

作者: GateKiller 发布者: 2008 年 8 月 5 日

15

17471 作者的声誉

不要没有null对象。你可以查看http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx获取更多信息,但设置的东西除了脏代码之外,null将不会执行任何操作。

作者: Karl Seguin 发布者: 2008 年 8 月 5 日

5

68776 作者的声誉

您应该将变量设置为null的唯一时间是变量不超出范围并且您不再需要与其关联的数据。否则就没有必要了。

作者: Bob 发布者: 2008 年 8 月 5 日

7

5548 作者的声誉

也:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
作者: Steve Tranby 发布者: 2008 年 8 月 5 日

1

60466 作者的声誉

在某些情况下,引用null是有意义的。例如,当您编写集合(如优先级队列)时,根据您的合同,在客户端将其从队列中删除后,您不应该为客户端保留这些对象。

但是这种事情只适用于长期存在的收藏品。如果队列不会在它创建的函数结束时存活下来,那么它就更不重要了。

总的来说,你真的不应该打扰。让编译器和GC完成他们的工作,这样你就可以做你的工作了。

作者: Patrick 发布者: 2008 年 8 月 5 日

68

98134 作者的声誉

决定

Karl绝对正确,使用后无需将对象设置为null。如果一个对象实现了IDisposable,只要确保IDisposable.Dispose()在完成该对象时调用(包装在try.. finally,或者一个using()块中)。但即使你不记得打电话Dispose(),对象的终结者方法应该是Dispose()你。

我认为这是一个很好的待遇:

深入了解IDisposable

还有这个

了解IDisposable

尝试再次猜测GC及其管理策略没有任何意义,因为它是自我调整和不透明的。关于Jeffrey Richter在Dot Net Rocks上的内部运作有一个很好的讨论:Jeff Memory Rich 在Windows内存模型和Richters的书中通过C#第20章预订CLR有一个很好的处理:

作者: Kev 发布者: 2008 年 8 月 5 日

7

7716 作者的声誉

一般来说,使用后不需要空对象,但在某些情况下我发现这是一个很好的做法。

如果一个对象实现了IDisposable并存储在一个字段中,我认为将其置零是好的,只是为了避免使用被处置的对象。以下类型的错误可能会很痛苦:

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

在处理之后将字段置零是很好的,并且在再次使用该字段的行处获得NullPtrEx。否则,你可能会遇到一些神秘的错误(具体取决于DoSomething的作用)。

作者: dbkk 发布者: 2008 年 8 月 9 日

7

30163 作者的声誉

如果您觉得需要null变量,那么您的代码可能不够紧密。

有许多方法可以限制变量的范围:

正如Steve Tranby所说

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

同样,您可以简单地使用花括号:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

我发现使用没有任何“标题”的大括号来真正清理代码并使其更容易理解。

作者: mbillard 发布者: 2008 年 8 月 9 日

35

20746 作者的声誉

避免在完成对象时将对象设置为null的另一个原因是它实际上可以使它们保持活动更长时间。

例如

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

在调用“DoSomething”之后,允许someType引用的对象为GC'd

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

有时可能会保持对象存活直到方法结束。在JIT通常会优化掉分配为空的,所以码两个位最终是相同的。

作者: Wilka 发布者: 2008 年 8 月 15 日

1

35251 作者的声誉

看一下这篇文章:http//www.codeproject.com/KB/cs/idisposable.aspx

在大多数情况下,将对象设置为null无效。你应该确定这样做的唯一时间是你使用的是一个大于84K的“大对象”(比如位图)。

作者: Scott Dorman 发布者: 2008 年 8 月 17 日

3

107 作者的声誉

这种“使用后无需将对象设置为null”并不完全准确。在处理变量后,有时需要对变量进行NULL操作。

是的,当你完成时,你应该总是打电话.Dispose()或打电话.Close()。无论是文件句柄,数据库连接还是一次性对象。

与此分开是LazyLoad非常实用的模式。

说我有并实例化ObjAclass AClass A有一个叫做PropB的公共财产class B

在内部,PropB使用私有变量,_B默认为null。当PropB.Get()使用时,它会检查,看是否_PropB为空,如果是,则打开实例化所需的资源B进入_PropB。然后它返回_PropB

根据我的经验,这是一个非常有用的技巧。

需要null的地方是,如果您以某种方式重置或更改A的内容_PropB是之前值的子项A,则需要Dispose AND null out,_PropB以便LazyLoad可以重置以获取正确的值如果代码需要它。

如果您只是_PropB.Dispose()在预期LazyLoad的空检查成功后不久就会成功,那么它将不会为空,并且您将查看过时的数据。实际上,您必须Dispose()在确定后将其置零。

我当然希望不是这样,但我已经有了代码,现在展出后,这种行为Dispose()上的_PropB和做的Dispose(因此几乎超出范围),专用道具仍然不为空,则调用函数外,而陈旧的数据仍在那里。

最终,被处置的财产将无效,但从我的角度来看,这是不确定的。

核心原因,正如dbkk所暗示的那样,父容器(ObjAwith PropB)保留了_PropB范围内的实例,尽管如此Dispose()

作者: KenF 发布者: 2012 年 4 月 11 日

5

739 作者的声誉

通常不需要设置为null。但假设您的班级中有重置功能。

然后你可能会这样做,因为你不想两次调用dispose,因为某些Dispose可能无法正确实现并抛出System.ObjectDisposed异常。

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
作者: Munish Goyal 发布者: 2012 年 4 月 17 日

0

147 作者的声誉

我相信通过GC实现器的设计,您无法通过无效来加速 GC。我敢肯定他们更愿意你不担心GC如何/何时运行 - 像对待它一样无处不在正在为你保护和监视......(低头向下,向天空举起拳头)...... 。

就个人而言,当我将变量作为一种自我文档形式完成时,我经常将变量显式设置为null。我没有声明,使用,然后设置为null - 我不再需要它后立即为null。我明确地说,“我已经正式完成了你......走了......”

在GC'd语言中是否需要取消?不。它对GC有用吗?也许是的,也许不是,不确定,通过设计我真的无法控制它,无论今天这个版本的答案如何,未来的GC实施可能会改变我无法控制的答案。如果/当归零被优化时,如果你愿意的话,它只是一个花哨的评论

我想,如果它让我的意图更清楚,那个跟随我的脚步的下一个可怜的傻瓜,如果它“可能”有时可能帮助GC,那么它对我来说是值得的。大多数情况下,它让我感到整洁和清晰,而Mongo喜欢整洁和清晰。:)

我这样看:编程语言的存在是为了让人们给别人一个意图的想法,一个编译器就可以做什么的工作请求 - 编译器将该请求转换为CPU的不同语言(有时是几个) - CPU可以提供您使用的语言,选项卡设置,注释,样式重点,变量名称等等。 - CPU的所有关于比特流的信息告诉它什么寄存器和操作码以及存储位置可以旋转。用代码编写的许多东西都不能转换成我们指定的序列中CPU所消耗的东西。我们的C,C ++,C#,Lisp,Babel,汇编程序或其他什么是理论而不是现实,写成工作陈述。你看到的不是你得到的,是的,即使是汇编语言。

我确实理解“不必要的东西”(如空白行)的心态“只不过是噪音和杂乱的代码。” 那是我职业生涯的早期; 我完全明白了。在这个时刻,我倾向于使代码更清晰的东西。这并不像我在我的程序中添加了50行“噪音” - 这里或那里有几行。

任何规则都有例外。在具有易失性内存,静态内存,竞争条件,单例,“陈​​旧”数据的使用以及所有那种腐烂的情况下,这是不同的:您需要管理自己的内存,锁定和取消作为apropos因为内存不属于GC'd Universe - 希望每个人都明白这一点。其余的时间使用GC语言,这是一种风格而非必要性或保证性能提升的问题。

在一天结束时,请确保您了解哪些符合GC条件,哪些不符合条件; 适当地锁定,处置和取消; 打蜡,打蜡; 呼吸,呼气; 对于我说的其他一切:如果感觉良好,那就去做吧。你的里程可能会有所不同......因为它应该......

作者: John 发布者: 2016 年 5 月 10 日

0

130 作者的声誉

Stephen Cleary在这篇文章中解释得非常好:我应该设置变量为空以协助垃圾收集吗?

说:

简短答案,对于不耐烦是,如果变量是静态字段,或者您正在编写可枚举方法(使用yield return)或异步方法(使用async和await)。否则,没有。

这意味着在常规方法(非可枚举和非异步)中,不要将局部变量,方法参数或实例字段设置为null。

(即使您正在实现IDisposable.Dispose,仍然不应将变量设置为null)。

我们应该考虑的重要事项是静态字段

静态字段始终是根对象,因此垃圾收集器始终将它们视为“活动”。如果静态字段引用不再需要的对象,则应将其设置为null,以便垃圾收集器将其视为符合收集条件。

如果整个过程正在关闭,则将静态字段设置为null是没有意义的。整个堆将在那时被垃圾收集,包括所有根对象。

大段引用

结论:

静态场; 这就是它。别的什么都浪费时间。

作者: Ebleme 发布者: 2019 年 3 月 27 日
32x32