未托管资源和Dispose()

3

我正在阅读一些关于Dispose()方法的文章,并发现非托管资源应该从Dispose()方法(或finalize()方法)中显式释放。文章说文件句柄和数据库连接对象是非托管资源的例子。有人能解释一下为什么它们是非托管资源,如果在Dispose()中没有正确处理会发生什么吗?我不知道文件句柄是什么,它们存在于哪里?

2个回答

13

在这个背景下,或许最容易理解的方式是:

  • 未托管的资源是指通过调用返回必须在某个时刻释放Windows Handle 的 Windows API 调用获得的任何资源。

  • 唯一的其他类型资源是内存。如果 .Net 分配了内存,则可以自动进行管理。(请注意,有使用 Windows API 分配内存的方法;这被视为未托管的资源。)

例如,FileStream 类调用 Windows API 打开文件,因此 FileStream 在内部维护了一个文件句柄。该文件句柄表示必须在某个时刻释放的未托管资源。

FileStream 在后台使用了 Windows API 函数CreateFile()。由CreateFile 返回的句柄表示未托管的资源。

如果您不释放这些句柄,则它们将在程序运行期间保持分配状态,但所有具有未托管资源的 .Net 类都提供了一个Finalizer(请参阅下文),以确保它们通常会在某个时刻被释放。

(但是,如果您编写自己的文件处理类并忘记在任何地方释放文件句柄,该文件将保持打开状态,直到程序退出。)

通常情况下,这些未托管资源将在两个位置被释放:

  • Dispose() 方法。这应该是正常处理未托管资源的方式。

  • Finalizer。这是一种最后的手段。如果一个类拥有 finalizer,当垃圾回收器清理一个已经死亡的对象时它将被调用。任何拥有非托管资源的类应该拥有 finalizer,以便在程序员忘记调用 Dispose() 方法时进行清理。

这有点简化了,但我希望这能帮助您理解。

有关完整细节,请参见此处的 MSDN 文章


4
有些人认为未经管理的资源与Windows API调用或其他类似事物有关,但这是实现细节。未经管理的资源的基本特征是,它代表了一个外部实体状态的方面,这个状态正在为拥有该资源的对象的利益而维护,可能会对其他实体产生不利影响,并且如果所有对该对象的引用都被放弃,那么外部实体将继续无用地维护这个状态。注意,外部实体可以是任何地方的任何东西。Windows API句柄只代表可能性的一小部分(获取句柄的对象请求Windows使系统的一些方面可供其独占使用,这对想要使用它们的任何其他代码都是不利的)。完全有可能外部实体在同一个程序集中(特别是如果资源是锁定或事件订阅),或者它可能在另一个大陆上(如果资源是远程计算机上的文件)。
一个对象通过通知代表它的实体不再需要这样做来释放资源。托管资源是一个.NET堆对象,它可能拥有一些托管或未经管理的资源的组合,但如果它被放弃,它的资源很可能会被释放。

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