在.NET中使用后将对象设置为Null / Nothing
一旦你完成了它们,你应该把所有的对象都设置为null
(VB.NET中Nothing
)
我知道,在.NET中,处理实现IDisposable
接口的对象的任何实例都是必要的,以释放一些资源,尽pipe对象在处置后仍然可以是某种东西(因此在表单中是isDisposed
属性),所以我认为它可以仍然驻留在记忆中,或至less部分存在?
我也知道,当一个对象超出范围时,它将被标记为垃圾收集器的下一个传递的收集(尽pipe这可能需要时间)。
所以考虑到这一点,将它设置null
速度释放内存的系统,因为它不需要解决它不在范围内,并且是否有任何不良副作用?
MSDN文章从来没有在例子中做到这一点,目前我这样做,因为我不能看到伤害。 不过,我遇到了各种意见,所以任何意见都是有用的。
Karl绝对正确,使用后不需要将对象设置为null。 如果一个对象实现了IDisposable
,只要确保在完成对象(包装在try
… finally
,或者using()
块)中时调用IDisposable.Dispose()
)。 但即使您不记得调用Dispose()
,对象上的终止方法也应该为您调用Dispose()
。
我认为这是一个很好的待遇:
挖入IDisposable
和这个
了解IDisposable
试图再次猜测GC及其pipe理策略是没有意义的,因为它是自我调整和不透明的。 关于Dot Net Rocks上的Jeffrey Richter的内部工作有一个很好的讨论: 在Windows内存模型上的Jeffrey Richter和通过C#第20章的Richters书CLR有一个很好的处理:
避免将对象设置为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通常会优化分配给null ,所以两个代码的结尾是一样的。
一般来说,使用后不需要空物体,但在某些情况下,我觉得这是一个很好的做法。
如果一个对象实现IDisposable并存储在一个字段中,我认为这是很好的,以避免使用处置对象。 下面的错误可能是痛苦的:
this.myField.Dispose(); // ... at some later time this.myField.DoSomething();
在处理完字段之后,将字段置零是很好的,然后在再次使用该字段的行上获得NullPtrEx。 否则,你可能会遇到一些神秘的bug(取决于DoSomething究竟是什么)。
也:
using(SomeObject object = new SomeObject()) { // do stuff with the object } // the object will be disposed of
如果你感觉需要null
variables的话,你的代码结构可能不够紧密。
有很多方法可以限制variables的范围:
正如史蒂夫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
我发现使用没有任何“标题”的大括号来真正清理代码,并使其更容易理解。
一般不需要设置为null。 但是,假设你有一个复位function在你的课堂上。
那么你可能会这样做,因为你不想调用两次configuration,因为一些Dispose可能没有被正确的实现并抛出System.ObjectDisposedexception。
private void Reset() { if(_dataset != null) { _dataset.Dispose(); _dataset = null; } //..More such member variables like oracle connection etc. _oraConnection }
唯一的一次你应该设置一个variables为null是当variables没有超出范围,你不再需要与它相关的数据。 否则没有必要。
这种“使用后不需要将对象设置为null”并不完全准确。 有些时候你需要在处理完variables后清空这个variables。
是的,你应该总是调用.Dispose()
或.Close()
的任何东西,当你完成。 无论是文件句柄,数据库连接还是一次性对象。
与此不同的是LazyLoad的实际模式。
假设我已经实例化了class A
ObjA
。 Class A
有一个名为class B
PropB
的公共财产。
在内部, PropB
使用_B
的私有variables,默认为null。 当使用PropB.Get()
,它会检查_PropB
是否为null,如果是,则打开实例化B
到_PropB
所需的资源。 然后它返回_PropB
。
根据我的经验,这是一个非常有用的技巧。
在需要null的地方进来的是,如果你重置或者改变A的方式,使得_PropB
的内容是前A
值的子_PropB
,那么你将需要Dispose并且_PropB
这样_PropB
可以重置来获取正确的值如果代码需要它。
如果只执行_PropB.Dispose()
并且在期望_PropB.Dispose()
的空检查成功之后不久,它将不会为空,并且您将查看陈旧的数据。 实际上,您必须在Dispose()
之后将其清零。
我当然希望它是在其他方面,但我现在有一个代码现在展示这个行为之后,在一个_PropB
Dispose()
之外的调用函数,并做了Dispose(因此几乎超出范围),私人道具仍然不是't null,陈旧的数据仍然存在。
最终,被处置的财产将被清空,但从我的angular度来看,这是不确定的。
dbkk的一个核心原因是父容器( ObjA
和PropB
)将_PropB
的实例_PropB
在范围内,尽pipeDispose()
。
在某些情况下,空引用是有意义的。 例如,当你正在编写一个集合 – 比如一个优先级队列 – 和你的契约时,在客户端将它们从队列中删除之后,你不应该让这些对象保留在客户端中。
但是这种事情只在长寿的collections中才有意义。 如果这个队列不能在它创build的函数结束的时候存活下来,那么它就不那么重要了。
总的来说,你真的不应该打扰。 让编译器和GC做他们的工作,所以你可以做你的工作。
看看这篇文章: http : //www.codeproject.com/KB/cs/idisposable.aspx
大多数情况下,将对象设置为null不起作用。 你唯一应该确定的是,如果你正在处理一个大于84K大小的“大对象”(比如位图)。
我相信通过GC实现者的devise,你不能加速 GC的无效化。 我敢肯定,他们更喜欢你不要担心自己在GC运行的时候怎么样 – 把它当作无处不在的正在为你保护和监视…(低着头,向天空挥拳)。 。
就我个人而言,当我把它们作为自我文档的一种forms完成时,我经常明确地将variables设置为null。 我没有声明,使用,然后设置为null – 我不再需要时立即null。 我明确地说,“我已经正式和你做了…走了……”
GC'd语言是否需要废止? 没有。对GC有帮助吗? 也许是的,也许不是,肯定不知道,在devise上,我真的无法控制它,不pipe今天的答案是这个版本还是那个,未来的GC实现可能会改变超出我的控制范围的答案。 另外如果/当nulling被优化出来,它只是一个奇特的评论,如果你愿意。
我想,如果这让我更加清楚下一个跟随我脚步的可怜的笨蛋,而且如果“有可能”有时帮助GC,那么这对我来说是值得的。 大部分是让我感觉整洁,蒙牛喜欢整洁。 🙂
我看起来就像这样:编程语言的存在是为了让别人给他们一个意图的概念,一个编译器提供一个工作请求 – 编译器把这个请求转换成一个不同的语言(有时候是几个CPU) CPU可以提供你所使用的语言,你的标签设置,注释,风格重点,variables名等等.CPU的所有关于比特stream的信息都告诉它哪些寄存器,操作码和内存位置是否可以旋转。 用代码编写的许多东西不会按照我们指定的顺序转换成CPU所消耗的东西。 我们的C,C ++,C#,Lisp,Babel,汇编程序或者任何其他理论而不是现实,都是作为工作陈述书写的。 你看到的不是你所得到的,是的,即使是汇编语言。
我明白“不必要的东西”(如空白行)的思维方式“只是噪音和混乱的代码”。 那是我职业生涯的早些时候, 我完全明白这一点。 在这个时候,我倾向于使代码更清晰。 这不像我在我的程序中添加50行“噪音” – 这里或那里只有几行。
任何规则都有例外。 在具有易失性存储器,静态存储器,竞态条件,单例,使用“过时”数据以及所有types的情况下,这是不同的:你需要pipe理自己的内存,locking和取消作为apropos,因为内存不是GC'd宇宙 – 希望每个人都明白这一点。 剩下的时间与GC'd语言是一个风格而不是必要的问题或保证性能提升。
在这一天结束的时候,确保你了解什么是符合GC的条件,什么不是。 locking,处理和废除适当的; 打蜡,打蜡; 呼吸,呼吸 对于我所说的一切,如果感觉良好,就去做吧。 你的里程可能会有所不同,因为它应该…
一些对象假设强制将资源从内存中移除的.dispose()
方法。