首页 / 知识
关于.net:垃圾收集器会致电IDisposable。为我处理?
2023-04-14 06:45:00

Will the Garbage Collector call IDisposable.Dispose for me?
.NET IDisposable模式意味着,如果编写终结器并实现IDisposable,则终结器需要显式调用Dispose。 但是,如果我这样做,会发生什么:
并且不要实现终结器或其他任何东西。框架会为我调用Dispose方法吗? 是的,我意识到这听起来很愚蠢,所有逻辑都暗示这不会,但是我总是有两件事让我不 几年前有人告诉我,实际上它会这样做,而且那个人在"知道自己的东西"方面有着非常可靠的记录。 编译器/框架根据实现的接口(例如:foreach,扩展方法,基于属性的序列化等)来执行其他"魔术"操作,因此这也可能是"魔术"的。 尽管我已经阅读了很多有关此书的内容,并且暗示了很多内容,但我始终无法找到该问题的明确答案"是"或"否"。 .Net垃圾收集器在垃圾收集上调用对象的Object.Finalize方法。默认情况下,此操作不执行任何操作,如果要释放其他资源,则必须将其忽略。 如果要释放资源(例如在"使用"或"最终尝试"块中),则不会自动调用Dispose,而必须显式调用Dispose。 有关更多信息,请参见http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx 我想在他的评论中强调布莱恩的观点,因为它很重要。 终结器不是像C ++中那样的确定性析构函数。正如其他人指出的那样,不能保证何时调用它,实际上不能保证是否有足够的内存可以调用。 但是,关于终结器的坏处在于,正如Brian所说,它会使您的对象在垃圾回收中幸存下来。这可能是不好的。为什么? 您可能知道也可能不知道,GC分为几代-第0代,第1代和第2代,以及大对象堆。拆分是一个宽松的术语-您可以获得一块内存,但是有第0代对象开始和结束位置的指针。 思考过程是,您可能会使用许多寿命短的对象。因此,对于GC来说-Gen 0对象应该简单,快速。因此,当存在内存压力时,它要做的第一件事就是Gen 0集合。 现在,如果那不能解决足够的压力,则返回并执行Gen 1扫描(重做Gen 0),然后如果仍然不够,则执行Gen 2扫描(重做Gen 1和Gen 0)。因此清理长寿命的对象可能要花一些时间,而且相当昂贵(因为在操作过程中可能会挂起线程)。 这意味着,如果您执行以下操作:
无论如何,您的对象都将保留到第二代。这是因为GC无法在垃圾回收期间调用终结器。因此,必须要终结的对象被移到一个特殊的队列中,以由另一个线程(终结器线程-如果杀死它会导致各种坏事)清除。这意味着您的对象会停留更长的时间,并可能导致更多的垃圾回收。 因此,所有这些只是为了传达您希望使用IDisposable尽可能清除资源的观点,并认真尝试寻找使用终结器的方法。这符合您的应用程序的最大利益。 这里已经有很多很好的讨论了,我参加聚会有点晚了,但是我想自己补充一点。
那是简单的版本,但是有很多细微差别可以使您陷入这种模式。
我认为,最好完全避免使用直接包含一次性引用和可能需要最终确定的本机资源的任何类型。 SafeHandles通过将本机资源封装到可在内部提供自己的终结处理的一次性资源中提供了一种非常干净的方式(以及许多其他好处,例如在P / Invoke期间删除窗口,由于异步异常,该窗口可能会丢失本机句柄) 。 只需定义一个SafeHandle就可以做到这一点:
允许您将包含类型简化为:
我不这么认为。您可以控制何时调用Dispose,这意味着从理论上讲您可以编写对(例如)其他对象的存在进行假设的处理代码。您无法控制何时调用终结器,因此让终结器代表您自动调用Dispose会很困难。 编辑:我去测试,只是为了确保:
并非您描述的那样 然而。下一个垃圾回收而不是被回收,对象将进入终结队列,所有内容都被收集,然后调用终结器。之后的下一个集合将被释放。 根据您的应用程序的内存压力,您可能会暂时没有gc来生成该对象。因此,就文件流或db连接而言,您可能需要等待一会儿,以便在finalizer调用中释放非托管资源一会儿,从而导致一些问题。 GC将不会调用处置。它可能会调用您的终结器,但即使在所有情况下也无法保证。 有关解决此问题的最佳方法的讨论,请参见本文。 不,它没有被调用。
但这很容易使您不要忘记布置对象。只需使用 为此,我做了以下测试:
如果您有一个实现IDispose的对象,则IDisposable模式主要是由开发人员创建的,如果开发人员应该在对象的上下文周围实现 模式的故障保护是实现终结器,调用Dispose()方法。如果不这样做,可能会造成一些内存泄漏,即:如果创建一些COM包装程序并且从不调用System.Runtime.Interop.Marshall.ReleaseComObject(comObject)(将其放置在Dispose方法中)。 除了跟踪包含终结器的对象并由GC将它们存储在Finalizer表中,然后由GC进行一些清理启发式调用时,clr中自动调用Dispose方法没有什么魔术。
有关IDisposable的文档对行为以及示例代码进行了非常清晰,详细的说明。 GC不会在接口上调用 |
最新内容
相关内容
linux命令模式全屏?
linux命令模式全屏?,系统,工具,电脑,数据,位置,命令,虚拟机,分辨率,字符串,窗口,linux命令行模式满屏如何翻页或dmesg |less more命令的翻页按调用函数命令linux?
调用函数命令linux?,系统,管理,网络,通用,统一,观察,地址,代码,设备,地方,怎么调用system函数,使用Android的linux命令1、int system(const chlinux中回到命令模式?
linux中回到命令模式?,系统,密码,情况,状态,终端,环境,信息,首页,界面,命令,“linux”怎么返回输入命令的状态?1、如果在命令行下使用gedit, 关linux命令行模式6?
linux命令行模式6?,系统,设计,信息,工作,终端,首页,庞大,服务,地方,环境,linux的运行模式1、Disable工作模式(关闭模式)在Disable模式中,SELinulinux怎么用命令模式?
linux怎么用命令模式?,工作,地址,系统,信息,管理,命令,目录,情况,图形界面,终端,linux系统常用操作命令1、linux常用命令有pwd命令、cd命令、llinux插入命令模式?
linux插入命令模式?,工作,系统,地址,管理,信息,时间,命令,目录,平均,项目,Linux命令1、linux系统常用操作命令如下:ls:全拼list,功能是列出目录的命令行模式登陆linux?
命令行模式登陆linux?,密码,系统,工作,信息,终端,环境,状态,地址,工具,服务,linux,按了ctrl+alt+F1,进入了类似纯命令行的界面,让输入login信linux打开命令模式?
linux打开命令模式?,系统,密码,管理,情况,终端,命令,工具,信息,地方,电脑,LINUX下怎么进入命令行模式,打开linux系统,在linux的桌面的空白处右linux内核总调用命令?
linux内核总调用命令?,工作,地址,系统,信息,管理,策略,命令,目录,时间,基础,如何在Linux内核里增加一个系统调用?在一个进程中创建3个线程,名字linux编程调用命令?
linux编程调用命令?,系统,标准,管理,工作,基础知识,情况,环境,设备,基础,首页,linux下怎样用c语言调用shell命令可以通过system函数,调用shelllinux纯命令模式切换?
linux纯命令模式切换?,系统,密码,状态,电脑,网络,信息,模式,命令,情况,地方,Linux切换命令模式与GUI模式手工切换:在图形界面中找一个可以输入linux命令底行模式?
linux命令底行模式?,系统,地址,工作,命令,管理,时间,信息,模式,控制台,图形界面,Linux下vim编辑器命令大全杀死进程killvi命令vi/vim是linux最