当我调用CLR时,object.Dispose()
是立即从内存中销毁对象,还是在下一个周期中将对象标记为删除?
我们在Dispose()之后立即调用GC.SuppressFinalize()
,这是否意味着“不要再为dispose收集对象,因为它已经提交给displose了”。
实际上,哪一代人应该对破坏负责,我猜是第二代。
发布于 2010-04-02 19:44:37
首先,IDisposable.Dispose
和GC不是一回事。
GC将清理内存使用,IDisposable.Dispose
用于确定地释放资源,如文件句柄、数据库连接、网络连接等。
让我们先来解决最终的问题。
如果一个对象声明了一个终结器,那么当GC将其从内存中释放出来时,该对象会被特殊对待。对象不是立即被释放,而是放在一个单独的列表中。
在后台,finalization线程正在运行此列表,并调用此列表上的对象的终结器方法。一旦调用了finalizer方法,该对象就会从列表中移除。
这里的要点是,当对象在此列表中时,它不符合收集的条件。这意味着,具有终结器的对象一旦符合收集条件,将临时转换为不再符合收集条件的状态,但等待完成。一旦对象再次被发现,在终结器运行并从列表中删除它之后,它将从内存中释放。
GC.SuppressFinalize
只是一个对象声明“终结器不再需要运行,如果你发现这个对象符合收集条件,就立即释放它”的一种方式。
另一方面,IDisposable.Dispose
一旦由对象实现,就不完全与垃圾收集器相关。GC系统中没有内置任何东西来确保调用Dispose
方法。这意味着在不调用Dispose
的情况下,可以轻松地释放具有Dispose
方法的对象。
此外,调用Dispose
也不会以任何方式使对象符合收集的条件。使对象符合收集条件的唯一方法是删除对它的所有强引用,通常是通过让局部变量超出作用域(方法返回)或通过从其他对象(如列表、事件处理程序等)中删除对该对象的任何引用。
“链接”,如果你想调用它,那就是,如果资源是非托管的,那么在内部拥有这样一个资源的对象通常会实现终结器。如果资源是托管资源,如FileStream
对象,则该对象将在需要时自行处理终结。但是,如果您持有非托管资源,比如通过P/Invoke检索到的文件句柄,那么您应该实现终结器。
通常,该对象的终结器和IDisposable.Dispose
都会清理该资源,然后Dispose
通常会调用GC.SuppressFinalize
来说:“我已经处理好了,如果对象符合收集条件,您可以释放它。”
但是,如果只调用Dispose
,但仍然保留对对象的引用(事件处理程序、静态字段、局部变量等)。则该对象还不符合收集的条件,并且不会被释放。
所以,总结一下:
Dispose
通常是为了释放资源(非托管或托管)。它不会以任何方式影响GC是否可以收集对象或何时收集对象。对象,在执行终结器之前,终结器将暂时放在列表中(因此不再适合收集
奖金问题
如果出现以下情况,您认为会发生什么:
希望这回答了你的问题,如果没有,请留下评论或澄清你的问题,我会编辑我的答案。
发布于 2010-04-02 19:35:48
CLR是一个通常会调用GC.SuppressFinalize
的普通Dispose
方法。垃圾收集器与此无关,并且调用Dispose
对GC没有特殊意义。
如果Dispose
调用GC.SuppressFinalize(this)
,则GC在收集对象时不会运行终结器。
然而,这并不意味着对象将被更快地收集。
发布于 2010-04-02 19:40:55
不,Dispose
不会导致垃圾回收器收集对象。您在许多Dispose
方法中看到GC.SuppressFinalize()
的原因是因为许多可处置类实现了终结器来确保处置。我会解释的。
如果我实现了一个包含关键资源的类,并且我想确保(好吧,几乎可以肯定)我的类得到了正确的处理,那么我可能不会仅仅依赖类的使用者来调用Dispose
或使用using
。相反,我可能会实现一个终结器,在大多数情况下,它将在GC收集我的对象时被调用。在终结器中,我将强制调用Dispose
。
但是对于垃圾收集器来说,带有终结器的对象更加复杂。它将挂起更长时间,占用更多内存,并且在收集时需要更多时间进行处理。
因此,如果用户确实记得正确处理,那么我们可以告诉GC,它不需要调用此对象的终结器。
https://stackoverflow.com/questions/2566377
复制相似问题