System.Runtime.InteropServices.SafeHandle 类

本文提供了此 API 参考文档的补充说明。

SafeHandle 类提供句柄资源的关键终结处理,防止句柄被垃圾回收机制过早回收,以及被操作系统回收后用于引用非预期的非托管对象。

为什么使用 SafeHandle?

尽管替代 Object.Finalize 方法允许在对对象进行垃圾回收时清理非托管资源,但在某些情况下,可以在平台调用中执行方法时通过垃圾回收来回收可终结的对象。 如果终结器释放了传递给该平台调用的句柄,则可能会导致句柄损坏。 在方法因平台调用(例如在读取文件时)被阻止的情况下,句柄也可能会被回收。

更重要的是,由于 Windows 积极回收句柄,一个句柄可能被回收并指向另一个可能包含敏感数据的资源。 这称为回收攻击,可能会损坏数据,并构成安全威胁。

SafeHandle 的作用

SafeHandle 类简化了其中几个对象生存期问题,并与平台调用集成,以避免操作系统资源泄露。 该 SafeHandle 类通过分配和释放句柄来解决对象生存期问题,而不会中断。 它包含一个关键终结器,可确保句柄已关闭,并保证在意外 AppDomain 卸载期间运行,即使在认为假定平台调用处于损坏状态的情况下也是如此。

由于 SafeHandle 继承自 CriticalFinalizerObject,所有非关键终结器都在所有关键终结器之前被调用。 对在同一垃圾回收过程中不再运行的对象调用终结器。 例如,FileStream 对象可以运行正常的终结器来刷新现有的缓冲数据,而不会有句柄泄露或被回收的风险。 关键终结器和非关键终结器之间的这种非常薄弱的排序不适用于常规用途。 它主要是为了帮助迁移现有库,通过允许它们在不改变语义的情况下使用 SafeHandle。 此外,关键终结器及其调用的任何内容(如 SafeHandle.ReleaseHandle() 该方法)必须位于受限的执行区域中。 这会对可在终结器调用图中编写哪些代码施加约束。

平台调用操作会自动递增 SafeHandle 封装的句柄的引用计数,并在完成后递减这些句柄。 这可确保句柄不会被意外回收或关闭。

在构造SafeHandle对象时,可以通过在ownsHandle类构造函数中的SafeHandle参数提供值来指定基础句柄的所有权。 这控制 SafeHandle 对象被处置后是否释放句柄。 这对于具有特殊生存期要求的句柄或使用其生存期由其他人控制的句柄非常有用。

派生自 SafeHandle 的类

SafeHandle 是操作系统句柄的抽象包装器类。 从此类派生比较困难。 但可以使用 Microsoft.Win32.SafeHandles 命名空间中可提供以下项的安全句柄的派生类。