终结器中处置的资源与处置中释放的资源有什么区别
What is the difference between the resources disposed in a finalizer to those released in dispose
这是这个问题的后续问题:
Finalize/Dispose pattern in C#
所以我明白,如果我正在创建一个使用非托管资源的 class,我应该处置它们。链接问题中的答案说终结器处理非托管资源。但是,Dispose(Boolean)
方法也在处理非托管资源:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
那么finalizer的处置和dispose方法的处置有什么区别呢?
你会使用它的唯一原因(而且它极具争议性)。
- 终结器允许在对象被垃圾收集器删除之前清除它。 (也就是说,GC负责调用它,并从内存中清除对象)如果开发者忘记调用对象的
Dispose()
方法,那么将有可能释放非托管资源,从而避免泄漏。
不这样做的原因有很多,弄错的方法也有很多。简而言之,您几乎没有理由需要这样做或想要这样做
除了给定的答案:终结器在运行时由垃圾收集器调用。
所以你不能指望在终结器中释放非托管资源的时间!因为未知。
此外,finalizer 在另一个线程上运行,因此当垃圾收集完成时,finalization 可能仍然是 运行!所以必须通过另一个垃圾收集,才能完全摆脱一个对象。
因此,第一次垃圾回收调用 finalezrs,但未收集对象(以及该对象持有引用的对象),它将在第二次垃圾回收中被收集。
一个带有finalizer的对象会经历GC的两个阶段:第一次,finalizer是运行,第二次,对象被真正回收,内存被释放。除了增加 GC 压力和延迟内存释放回池外,终结器还具有处理字段可能不处于有效状态的对象的功能。此外,在终结器线程上抛出异常会立即破坏整个应用程序,而没有任何关于刚刚发生的事情的友好信息。
这就是为什么 Dispose 模式实现总是以调用 GC.SuppressFinalize
为特色,这导致终结器不 运行 以防对象已经被释放并且 GC 可以首先直接释放内存运行.
通常,如果您的应用程序应该在内存不足或线程中止以及随后的 AppDomain 卸载等严重异常中幸存下来,那么使用终结器可能会非常复杂和棘手 - SQL Server 或IIS.
长话短说:除非万不得已,否则不要使用终结器,如果必须(例如,使用非托管资源),还有很多研究等着您。
您可以在以下博客文章中找到有关此主题的更多阅读材料:
这是这个问题的后续问题:
Finalize/Dispose pattern in C#
所以我明白,如果我正在创建一个使用非托管资源的 class,我应该处置它们。链接问题中的答案说终结器处理非托管资源。但是,Dispose(Boolean)
方法也在处理非托管资源:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// get rid of managed resources
}
// get rid of unmanaged resources
}
那么finalizer的处置和dispose方法的处置有什么区别呢?
你会使用它的唯一原因(而且它极具争议性)。
- 终结器允许在对象被垃圾收集器删除之前清除它。 (也就是说,GC负责调用它,并从内存中清除对象)如果开发者忘记调用对象的
Dispose()
方法,那么将有可能释放非托管资源,从而避免泄漏。
不这样做的原因有很多,弄错的方法也有很多。简而言之,您几乎没有理由需要这样做或想要这样做
除了给定的答案:终结器在运行时由垃圾收集器调用。
所以你不能指望在终结器中释放非托管资源的时间!因为未知。
此外,finalizer 在另一个线程上运行,因此当垃圾收集完成时,finalization 可能仍然是 运行!所以必须通过另一个垃圾收集,才能完全摆脱一个对象。
因此,第一次垃圾回收调用 finalezrs,但未收集对象(以及该对象持有引用的对象),它将在第二次垃圾回收中被收集。
一个带有finalizer的对象会经历GC的两个阶段:第一次,finalizer是运行,第二次,对象被真正回收,内存被释放。除了增加 GC 压力和延迟内存释放回池外,终结器还具有处理字段可能不处于有效状态的对象的功能。此外,在终结器线程上抛出异常会立即破坏整个应用程序,而没有任何关于刚刚发生的事情的友好信息。
这就是为什么 Dispose 模式实现总是以调用 GC.SuppressFinalize
为特色,这导致终结器不 运行 以防对象已经被释放并且 GC 可以首先直接释放内存运行.
通常,如果您的应用程序应该在内存不足或线程中止以及随后的 AppDomain 卸载等严重异常中幸存下来,那么使用终结器可能会非常复杂和棘手 - SQL Server 或IIS.
长话短说:除非万不得已,否则不要使用终结器,如果必须(例如,使用非托管资源),还有很多研究等着您。
您可以在以下博客文章中找到有关此主题的更多阅读材料: