什么时候 dispose 方法不会被调用?
前几天我正在阅读这篇文章,并且是想知道为什么除了 Dispose 方法之外还有 Finalizer。我在此处阅读了关于为什么您可能想要将 Dispose 添加到终结器。我好奇的是,什么时候 Finalizer 会通过 Dispose 方法本身被调用?是否有代码示例,或者它是基于软件运行的系统上发生的事情?如果是这样,GC 不运行 Dispose 方法会发生什么情况。
I was reading this article the other day and was wondering why there was a Finalizer along with the Dispose method. I read here on SO as to why you might want to add Dispose to the Finalizer. My curiousity is, when would the Finalizer be called over the Dispose method itself? Is there a code example or is it based on something happening on the system the software is running? If so, what could happen to not have the Dispose method run by the GC.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这里终结器的目的只是为了防止内存泄漏(如果您碰巧没有显式调用
Dispose
)。这也意味着如果您希望对象在程序关闭时释放资源,则不必处置对象,因为 GC 无论如何都会被迫完成并收集所有对象。与此相关的是,在处理对象时,与终结器略有不同非常重要。
您不想在终结器中处置托管资源的原因是,这样做实际上会创建对它们的强引用,这可能会阻止 GC 正确完成其工作并收集它们。当然,非托管资源(例如 Win32 句柄等)应始终显式关闭/处置,因为 CLR 不了解它们。
The purpose of the finaliser here is simply a safety precaution against memory leaks (if you happen not to call
Dispose
explicitly). It also means you don't have to dispose your objects if you want them to release resources when the program shutdowns, since the GC will be forced to finalise and collect all objects anyway.As a related point, it is important to dispose the object slightly differently when doing so from the finaliser.
The reason you do not want to dispose managed resources in your finaliser is that you would actually be creating strong references to them in doing so, and this could prevent the GC from doing it's job properly and collecting them. Unmanaged resources (e.g. Win32 handles and such) should always be explicitly closed/disposed, of course, since the CLR has no knowledge of them.
这主要是为了保护自己。您无法规定您的班级的最终用户将做什么。通过除了 Dispose 方法之外还提供终结器,GC 将“处置”您的对象,从而适当地释放您的资源,即使用户忘记调用 Dispose() 或误用您的类也是如此。
This is mostly there to protect yourself. You cannot dictate what the end user of your class will do. By providing a finalizer in addition to a Dispose method, the GC will "Dispose" of your object, freeing your resources appropriately, even if the user forgets to call Dispose() or mis-uses your class.
当对象被垃圾回收时,Finalizer 被调用。需要显式调用 Dispose。在下面的代码中,将调用终结器,但不会调用 Dispose 方法。
The Finalizer is called when the object is garbage collected. Dispose needs to be explicitly called. In the following code the finalizer will be called but the Dispose method is not.
必须显式调用 dispose 方法,可以通过调用 Dispose() 或将对象放在 using 语句中。 GC 将始终调用终结器,因此如果在对象被处置之前需要发生某些事情,则终结器至少应该检查以确保对象中的所有内容都已清理。
如果可能的话,您希望避免清理终结器中的对象,因为与事先处理它们(例如调用 dispose)相比,它会导致额外的工作,但您应该始终至少检查终结器中是否存在需要的对象被删除。
The dispose method must be explicitly called, either by calling Dispose() or by having the object in a using statement. The GC will always call the finalizer, so if there is something that needs to happen before the objects are disposed of the finalizer should at least check to make sure that everything in the object is cleaned up.
You want to avoid cleaning up objects in the finalizer if at all possible, because it causes extra work compared to disposing them before hand (like calling dispose), but you should always at least check in the finalizer if there are objects lying around that need to be removed.
一个重要但微妙的注释尚未提及:Dispose 的一个很少被考虑的目的是防止对象被过早清理。必须仔细编写带有终结器的对象,以免终结器比预期早运行。终结器不能在对对象 (*) 进行的最后一个方法调用开始之前运行,但如果一旦对象将被放弃,它有时可能会在最后一个方法调用期间运行。方法完成。正确处理对象的代码不能在调用 Dispose 之前放弃该对象,因此终结器不会对正确使用 Dispose 的代码造成严重破坏。另一方面,如果最后一个使用对象的方法使用了在最后一次使用对象引用本身后将在终结器中清理的实体,则垃圾收集器可以在该对象上调用 Finalize 并清理仍在使用的实体。补救措施是确保任何使用将由终结器清理的实体的调用方法必须在某个时刻跟随使用“this”的方法调用。 GC.KeepAlive(this) 是一个很好的方法。
(*) 扩展为不对对象执行任何操作的内联代码的非虚拟方法可能不受此规则的约束,但 Dispose 通常是或调用虚拟方法。
An important but subtle note not yet mentioned: a seldom-considered purpose of Dispose is to prevent an object from being cleaned up prematurely. Objects with finalizers must be written carefully, lest a finalizer run earlier than expected. A finalizer can't run before the start of the last method call that will be made on an object(*), but it might sometimes run during the last method call if the object will be abandoned once the method completes. Code which properly Dispose an object can't abandon the object before calling Dispose, so there's no danger of a finalizer wreaking havoc on code which properly uses Dispose. On the other hand, if the last method to use an object makes use of entities which will be cleaned up in the finalizer after its last use of the object reference itself, it's possible for the garbage-collector to call Finalize on the object and clean up entities that are still in use. The remedy is to ensure any call method which uses entities that are going to get cleaned up by a finalizer must be followed at some point by a method call which makes use of "this". GC.KeepAlive(this) is a good method to use for that.
(*) Non-virtual methods which are expanded to in-line code that doesn't do anything with the object may be exempt from this rule, but Dispose usually is, or invokes, a virtual method.