为什么在 main() 结束之前要调用 Dispose() 方法?

11

我的 .net 服务在 Main() 循环退出之前,在 finally 块中调用 resourceName.Dispose() 来清理所有未托管的资源。

我真的需要这样做吗?

我是否正确地认为,因为进程正在结束,所以我不能泄漏任何资源?Windows 会关闭任何不再使用的句柄,对吗?

2个回答

9

在特定情况下跳过这一步可能是可以的。

首先要理解的是,尽管终止进程本身应该足以清理大部分内容,但是某些未受管理的资源可能会处于不良或未关闭状态。例如,您可能有一个按席位许可的应用程序,当应用程序关闭时,您需要更新某个数据库记录以释放许可证。如果进程意外终止,则没有任何东西会执行该更新,并且您可能最终无法使用软件。仅因为进程终止并不是不进行清理的借口。

然而,在实现IDisposable模式的.Net世界中,可以获得更多保险措施。当进程退出时,所有剩余的终结器都将运行。前提是Dispose()模式被正确实现(这比应该还要重要),终结器仍存在于其对象的任何剩余未托管资源的处理中……

但是,始终养成正确地自己处理这些事情的习惯是很好的实践。此外,只调用.Dispose()是不足以正确完成此操作的。您的.Dispose()调用必须包含在finally块中(包括使用using语句获取的隐式finally块)。


1
虽然这是关键,"如果Dispose()模式被正确实现的话"。因为这并不保证,所以最好总是自己处理IDisposable的对象,就像你建议的那样。 - moribvndvs
2
虽然这种情况可能没问题,但鼓励这种习惯是不好的。你永远不知道那段代码何时会被复制到另一个项目中进行研究和开发,然后就可能出现问题。每次都正确地做这个小细节,你就不用担心了。 - Jesse C. Slicer
仅仅因为一个类实现了IDisposable接口,并不意味着它也会有一个终结器。通常,Dispose方法用于清理托管和非托管资源(如果该类有任何这样的资源),而终结器则只是用于整理可能泄漏内存的非托管资源。 - Trevor Pilley
我对“这是一个坏习惯”的反驳是“不要写你不需要的代码”。 话虽如此,不清理资源的想法让我感到奇怪,这也是我首先提出问题的原因 :) - s d
请原谅我的直言:进程即将结束,为什么我需要处理该对象? - s d
显示剩余2条评论

9

IDisposable 接口实现的对象可以封装各种类型的资源,没有任何限制。大多数由 IDisposable 对象封装的资源将在进程关闭时由操作系统清理,但有些程序可能会使用操作系统不知道的资源。例如,需要一个底层数据库不支持的锁定模式的数据库应用程序可能使用一个或多个表来跟踪哪些内容被“签出”以及由谁签出。使用这些表检查资源的类可以确保在其 Dispose 方法中将所有内容都检查回来,但如果程序在类没有清理表的机会之前关闭,那么该表所守卫的资源将被留下。由于操作系统无法理解这些表的含义,因此它无法清理这些表和相关资源。


2
我认为这个答案最有道理:操作系统无法释放它不知道的资源。 - s d

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