运维开发网

C#Dispose() – 澄清

运维开发网 https://www.qedev.com 2020-04-03 17:28 出处:网络 作者:运维开发网整理
当我调用object.Dispose(); CLR会立即从内存中销毁对象,还是在下一个循环中标记要删除的对象? 我们在Dispose()之后立即调用GC.SuppressFinalize(),这是否意味着,“不要再为了dispose收集对象,因为它已经提交给了displose”. 实际上哪一代负责破坏,我猜第2代. 首先,IDisposable.Dispose和GC并不是一回事. GC将清理内存使
当我调用object.Dispose(); CLR会立即从内存中销毁对象,还是在下一个循环中标记要删除的对象?

我们在Dispose()之后立即调用GC.SuppressFinalize(),这是否意味着,“不要再为了dispose收集对象,因为它已经提交给了displose”.

实际上哪一代负责破坏,我猜第2代.

首先,IDisposable.Dispose和GC并不是一回事.

GC将清理内存使用情况,IDisposable.Dispose用于确定性地释放资源,如文件句柄,数据库连接,网络连接等.

让我们先解决最终问题.

如果一个对象声明了一个终结器,那么当GC出现以将其从内存中释放时,该对象将被特别处理.该对象不是一次被释放,而是放在一个单独的列表中.

在后台,终结线程正在运行此列表并调用此列表中对象的终结器方法.调用终结器方法后,将从列表中删除该对象.

这里的要点是,虽然对象在此列表中,但它不符合收集条件.这意味着具有终结器的对象一旦有资格进行收集,将暂时转换为不再符合收集条件但尚未完成的状态.再次发现对象后,在终结器运行并从该列表中删除后,它将从内存中释放.

GC.SuppressFinalize只是一个对象说“终结器不再需要运行,如果你发现这个对象有资格收集,只需立即释放它”的一种方式.

IDisposable.Dispose,另一方面,一旦由一个对象实现,与垃圾收集器并不完全相关. GC系统中没有内置任何内容可确保调用Dispose方法.这意味着可以轻松释放具有Dispose方法的对象,而无需调用Dispose.

此外,调用Dispose不会以任何方式使对象符合收集条件.使对象符合收集条件的唯一方法是删除对它的所有强引用,通常是让局部变量超出范围(方法返回),或者从其他对象(如列表,事件处理程序,等等.)

如果要调用它,那么“链接”就是内部具有此类资源的对象通常会实现终结器(如果资源是非托管的).如果资源是托管的,就像FileStream对象一样,那么该对象将根据需要自行完成最终化.但是,如果您要保留非托管资源,例如通过P / Invoke检索的文件句柄,那么您应该实现终结器.

通常,该对象的终结器和IDisposable.Dispose都将清理该资源,然后它通常用于Dispose调用GC.SuppressFinalize以表示“我已经处理过它,你可以释放该对象,如果它是有资格领取.“

但是,如果您只是调用Dispose,但仍保留对该对象的引用(事件处理程序,静态字段,局部变量等),则该对象尚不符合收集条件且不会被释放.

所以,总结一下:

>调用Dispose通常用于释放资源(非托管或托管).它不会以任何方式影响GC是否可以收集对象,或者何时完成.

>使对象符合收集条件的唯一方法是明确丢失对它的所有强引用.

> GC调用终结器,通常用于释放非托管资源.

>有资格收集但有终结器的对象将暂时放在列表中(因此不再有资格收集),直到终结器被执行

奖金问题:

如果出现以下情况,您认为会怎样?

>终结者挂了吗? (通常(据我所知)只有一个终结器线程,如果它挂起,该列表上其余对象会发生什么?)

>一个对象使自己无法收集作为其终结器的一部分(通常通过将自身插入静态字段).终结器已经运行,并且有一个标记,因此一旦对象再次可用于收集,终结器将不会自动重新运行. GC对象中还有其他方法可以重新注册它以进行最终确定.

希望这能回答你的问题,如果没有,请发表评论或澄清你的问题,我会编辑我的答案.

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号