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

Joh*_*ohn 184 .net c# vb.net null memory-management

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

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

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

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

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

Kev*_*Kev 71

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有一个很好的处理:

  • "不要过早优化"的整个业务听起来更像是"喜欢慢,不要担心,因为CPU越来越快,CRUD应用程序无论如何都不需要速度." 可能只是我.:) (21认同)
  • 它的真正含义是"垃圾收集器在处理内存方面比你更好." 那可能只是我.:) (19认同)
  • 关于不设置为null的规则不是"硬而快"...如果对象放在大对象堆上(大小> 85K),如果在完成后将对象设置为null,它将帮助GC使用它. (6认同)
  • @BobbyShaftoe:说"过早的优化是坏的,总是"可能是错误的,因为它是跳到"听起来更像'喜欢慢'的相反极端." 没有合理的程序员会说.这是关于你的优化的细微差别和聪明.我个人担心代码清晰度和那种实际测试性能,因为我亲眼看到很多人(包括我年轻的时候)花费太多时间制作"完美"算法,只是为了节省0.1ms在所有可读性完全拍摄的同时进行100,000次迭代. (2认同)

Wil*_*lka 36

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

例如

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

    // ... rest of method not using 'someType' ...
}
Run Code Online (Sandbox Code Playgroud)

在调用"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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 确保它们保持活动状态的首选方法是使用 `GC.KeepAlive(someType);` 参见 http://ericlippert.com/2013/06/10/construction-destruction/ (2认同)

Kar*_*uin 14

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


Ste*_*nby 7

也:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
Run Code Online (Sandbox Code Playgroud)


dbk*_*bkk 7

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

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

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();
Run Code Online (Sandbox Code Playgroud)

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

  • 好吧,如果已经处置掉了一个被处置的对象,它应该抛出ObjectDisposedException.据我所知,这确实需要遍布整个地方的样板代码,但是再一次,Disposed无论如何都是一个经过深思熟虑的范例. (8认同)
  • Ctrl + F表示`.Dispose()`.如果找到它,则表示您没有正确使用IDisposable.一次性物体的唯一用途应该是使用块的范围.在使用块之后,您甚至无法访问"myField".在using块中,不需要设置为"null",using-block将为您配置对象. (3认同)

mbi*_*ard 7

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

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

正如Steve Tranby所说

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
Run Code Online (Sandbox Code Playgroud)

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

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

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


Bob*_*Bob 5

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

  • 这是真的,但这也意味着你应该重构你的代码.我认为我不需要在其预期范围之外声明变量. (2认同)
  • 如果"变量"被理解为包含对象字段,那么这个答案很有意义.在"变量"仅表示"局部变量"(方法)的情况下,我们可能在这里讨论利基案例(例如,运行时间长于通常时间跨度的方法). (2认同)

Mun*_*yal 5

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

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

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
Run Code Online (Sandbox Code Playgroud)