为了账号安全,请及时绑定邮箱和手机立即绑定

垃圾收集器是否会为我调用IDisposable.Dispose?

垃圾收集器是否会为我调用IDisposable.Dispose?

手掌心 2019-08-06 16:10:13
垃圾收集器是否会为我调用IDisposable.Dispose?.NET IDisposable Pattern 意味着如果您编写终结器并实现IDisposable,则终结器需要显式调用Dispose。这是合乎逻辑的,而且在极少数情况下我总是会做终结器的保证。但是,如果我这样做会发生什么:class Foo : IDisposable{      public void Dispose(){ CloseSomeHandle(); }}并且不要实现终结器或任何东西。框架会为我调用Dispose方法吗?是的,我意识到这听起来很愚蠢,而且所有的逻辑都暗示它不会,但我总是有两件事让我不确定。几年前有人曾告诉我,事实上它会这样做,而且那个人有“非常了解他们的东西”的良好记录。编译器/框架根据您实现的接口(例如:foreach,扩展方法,基于属性的序列化等)执行其他“神奇”操作,因此这也可能是“魔术”。虽然我已经阅读了很多关于它的内容,并且有很多暗示的内容,但我从来没有能够找到这个问题的肯定是或否答案。
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

我想强调Brian在评论中的观点,因为它很重要。

终结器不是像C ++那样的确定性析构函数。正如其他人所指出的那样,没有什么时候会被称为保证,而事实上,如果你有足够的内存,如果将永远被调用。

但是关于终结器的坏处是,正如Brian所说,它会使你的对象在垃圾收集中存活下来。这可能很糟糕。为什么?

正如您可能知道或不知道的那样,GC分为几代 - Gen 0,1和2,以及大对象堆。Split是一个松散的术语 - 你得到一块内存,但是有一些指向Gen 0对象的起点和终点。

思考过程是你可能会使用很多短暂的物体。因此,对于GC来说,这些应该是简单快速的 - Gen 0对象。因此,当存在内存压力时,它首先做的是Gen 0集合。

现在,如果它没有解决足够的压力,那么它会返回并进行第1代扫描(重做第0代),然后如果仍然不够,则执行第2代扫描(重做第1代和第0代)。因此,清理长寿命对象可能需要一段时间并且相当昂贵(因为您的线程可能在操作期间被挂起)。

这意味着,如果您执行以下操作:

~MyClass() { }

无论如何,您的对象都将存在于第2代。这是因为GC无法在垃圾回收期间调用终结器。所以必须最终确定的对象被移动到一个特殊的队列,由另一个线程清理掉(终结器线程 - 如果你杀了它就会发生各种坏事)。这意味着您的对象会更长时间地挂起,并可能会强制更多垃圾收集。

所以,所有这一切只是为了让你想要使用IDisposable来尽可能地清理资源,并认真尝试找到使用终结器的方法。这符合您的应用程序的最佳利益。


查看完整回答
反对 回复 2019-08-06
  • 3 回答
  • 0 关注
  • 499 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信