我需要确认一下您需要的语言是什么?是简体中文还是繁体中文?

8

我知道所有实现IDisposable接口的对象都应该在不再需要时立即被处理,以释放其非托管资源使用的内存。

我的问题与我所知道的会一直存在直到主机进程本身终止的对象有关。如果我对它们进行处理或不进行处理是否会有任何区别?在进程终止时是否有可能未释放内存?GDI对象呢?即使它们没有被处理,GDI句柄也会在进程终止时被释放吗?

我完全理解,无论如何处理所有对象都是良好的实践。我只是出于好奇而问。


哇,人们像一群狗对待三条腿的猫一样扑向我,因为我说不要处理。我发现它会带来更多的伤害而不是帮助。难道生命周期不应该由容器管理,而不是硬编码吗? - CrazyDart
@CrazyDart 谢谢,这是一篇有趣的阅读材料,尽管它主要涉及“类型为X的对象通常应该被处理”的问题。我试图回答的更具体的问题是:“即使对象的生命周期与进程相同,类型为X的必须被处理的对象是否应该被处理?” - Rotem
1
@CrazyDart,Dispose 什么时候伤害过你?你提供的链接给出了一些不应该调用 Dispose 的例子,但通常规则仍然是除非你有充分的理由不这样做,否则应该调用它。 - user743382
2个回答

7

这取决于所涉及的对象(资源)。

当进程终止时,所有未管理的内存、文件句柄和其他操作系统资源将被释放,即使相关的 finalizer 未能运行。

但是我不确定数据库句柄、命名互斥体等是否也会被释放。

因此,在您认为不需要调用 Dispose() 之前,您必须了解资源类型以及它与进程的关系。最好还是按照一般原则调用 Dispose()。

但这是一个理论上的论点,大多数类将使用 SafeHandle : CriticalFinalizerObject。因此,我不认为这是一个真正的实际问题。


默认情况下,每个具有终结器的对象都将运行其终结器。相反,您可以从代码中控制:您的 Dispose 可以调用 GC.SuppressFinalize 来表示不再需要终结器。(编辑:实际上,我认为每个对象都有一个终结器,但默认情况下它什么也不做。) - user743382
1
@hvd - 理论上,普通的终结器可能会被垃圾回收器跳过。 - H H
@hvd - "我认为每个对象都有一个终结器"是正确的,"但默认情况下它什么也不做"。这也是正确的,非常幸运。真正的终结器是昂贵的。 - H H
同意,这在C语言中被称为“as-if”规则,但是这个原则同样适用于其他编程语言和环境:如果一个程序无法判断终结器是否运行,因为终结器没有任何副作用,那么终结器就不需要运行。 - user743382
创建覆盖 Finalize 方法的对象时,会创建一种特殊的弱引用,并将其存储在覆盖 Finalize 方法的对象列表中,同时存储其他一些簿记信息。即使对象立即调用 GC.SuppressFinalize() 自身,也无法避免系统设置该引用所需执行的工作,也不会释放簿记信息,直到对象本身被收集。未覆盖 Finalize 方法的对象永远不会放置在列表上,并且通常不需要创建簿记信息。 - supercat

2

根据设计,IDisposable可用于使程序提前释放非托管资源,比终结器更早地释放。终结器在进行垃圾回收时通常会在稍后的时间运行,时间相当不确定。你无法预测何时会发生。

在程序退出时进行处理没有意义,因为终结器保证会在AppDomain卸载和进程关闭之前运行。

话虽如此,有一些滥用IDisposable的代码实际上期望你调用它。但这通常是基于“using”语句的,所以不太可能遇到这种情况。


1
终结器不能保证在程序退出时运行。系统保证会尽力运行它们,但这并不意味着它们实际上会被执行。终结器真的很棘手,大多数对象真的不应该有它们。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接