在试图理解 IDisposable 时,我有几个问题大多数答案都没有明确说明。
如果我们在一个对象上调用 dispose,那是在那个时候释放这个对象还是只释放我们想要清理的类成员,并且整个对象稍后会被 GC 销毁。
我们在 dispose 方法中抑制 finalizer 后,GC 是否还会清理所有我们在 dispose 中没有清理的类成员?
在试图理解 IDisposable 时,我有几个问题大多数答案都没有明确说明。
如果我们在一个对象上调用 dispose,那是在那个时候释放这个对象还是只释放我们想要清理的类成员,并且整个对象稍后会被 GC 销毁。
我们在 dispose 方法中抑制 finalizer 后,GC 是否还会清理所有我们在 dispose 中没有清理的类成员?
一旦对它的所有引用都消失了,就会以非确定性的方式对对象进行垃圾收集。 来自 MSDN 的垃圾收集: Garabge 收集基础
当下列条件之一为真时,就会发生垃圾收集:
- 系统物理内存不足。
- 托管堆上分配的对象使用的内存超过了可接受的阈值。这意味着已超过托管堆上可接受的内存使用量的阈值。随着流程的运行,此阈值会不断调整。
GC.Collect 方法被调用。在几乎所有情况下,您都不必调用此方法,因为垃圾收集器会持续运行。此方法主要用于特殊情况和测试。
首先,关于这个主题有很多重复的问题。如果真的没有其他答案明确回答您的问题,那么它们就是这样,但我希望这将作为重复关闭。
首先,Dispose
只是一种方法,一种普通的方法。它根本不处理垃圾收集。
那么 Dispose 是做什么的呢?它应该用于清理非托管资源,例如文件句柄、窗口句柄等。.NET 垃圾收集器不知道的事情。
所以回答问题 1:“是的”,当你调用Dispose
一个对象时,它会被放置在那里。类上没有设置标记以指示稍后进行清理。
由于 Dispose 不处理 Garbage Collection,因此您可以在 dispose 后轻松保留对对象的引用,并且不会被垃圾回收。垃圾回收仅在不再引用该对象时发生。即使您没有调用Dispose
对象,这也可能发生,但不会发生,因为您调用Dispose
了对象。
第二个问题:当 GC 在通过终结器循环后收集对象时,GC 将清理对象 + 它引用的任何不再有任何引用的对象(除了来自您的对象的引用)。这发生在某个时候,也不一定是同时发生的。
抑制终结器只是确保 GC 不会做不必要的工作,通过说“当你找到这个对象并确定它有资格收集时,继续收集它,我已经处理了'终结' 清理所以你不必“。
首先也是最重要的,您需要了解处理对象和垃圾收集对象是完全不同的事情——确保不要混淆两者!
如果我们在一个对象上调用 dispose,唯一发生的事情就是该Dispose
方法被调用。可能是该Dispose
方法然后继续调用GC.SuppressFinalize
,但是它可能根本不做任何事情-它完全取决于实现。
当我们调用时GC.SuppressFinalize
,唯一发生的事情是它要求 GC 在收集对象时不要调用对象终结器(几乎就像对象一开始没有终结器一样)。
碰巧的是,一个常见的模式是让具有终结器的对象也实现IDisposable
,以便可以确定性地清理非托管资源 - 如果发生这种情况,则 GC 不需要调用终结器,因为在当我们调用终结器时,已经执行了终结器Dispose
——调用GC.SuppressFinalize
只是对 GC 的友好提示,它实际上并不需要调用终结器。
1) 当您对一个对象调用 dispose 时,所发生的一切就是运行其 Dispose() 方法中的代码。这段代码当然可以为它的一个或多个字段调用 Dispose(),但这不是必须的。
它也可以调用基类' Dispose(true)
,如果有的话(通过base.Dispose()
),但那是使用 Dispose Idiom; Dispose(bool)
不是IDisposable
界面的一部分。
2) 仅针对调用 SuppressFinalize() 的特定对象抑制终结器。它不会影响任何其他对象(包括调用 SuppressFinalize() 的对象的字段所持有的任何对象)。