20

关于托管资源和非托管资源有很多问题。我了解两者的基本定义。但是,我很难知道资源或对象何时是托管的或非托管的。

当我想到非托管资源时,我倾向于想到不直接属于 .NET 的本机代码,例如 pinvoke 或封送资源。我通常会认为资源旨在与将使用硬件的东西接口,例如文件句柄或网络连接也不受管理。

包装原生非托管资源(如 .NET)的 .NET 对象呢FileStream

必须FileStream使用非托管资源,但是当我实现该IDisposable模式时,我应该将其视为托管资源还是非托管资源?

到目前为止,我一直假设如果对象实现了IDisposable,那么它是被管理的。我怎么知道IntPtr应该作为非托管资源处理?

4

3 回答 3

15

必须FileStream使用非托管资源,但是当我实现 IDisposable 模式时,我应该将其视为托管资源还是非托管资源?

FileStream 是一种托管资源

托管资源是包含(并且必须管理)非托管资源的类。通常实际资源是向下的几层。

到目前为止,我一直假设如果对象实现了IDisposable,那么它是被管理的。

正确的。

我怎么知道 IntPtr 应该作为非托管资源处理?

从您从中获得价值的 API 的文档中。但请注意,在实践中,大多数程序员从不直接处理非托管资源。当您必须这样做时,使用SafeHandle该类将非托管资源转换为托管资源。

于 2012-12-09T10:53:49.700 回答
10

这非常简单,您永远不会意外分配非托管资源。需要一个 pinvoke 调用来分配它,你会知道的。术语“对象”是重载的,但不存在非托管对象之类的东西,.NET 程序中的所有对象都是托管的。您可以与用另一种支持创建对象的语言(如 C++)编写的代码进行互操作。但是您不能直接使用这样的对象,需要 C++/CLI 包装器。这使它成为实现 IDisposable 的托管类。

如果您使用的是文档记录不佳的库,那么当您返回 IntPtr 时请务必注意。这是一个非常强烈的迹象,表明涉及到非托管分配,要么是指向非托管内存的指针,要么是操作系统句柄。如果它没有自动管理它,那么该库还应该为您提供一种释放它的方法。如果您不确定如何正确处理,请联系图书馆所有者。

围绕所有常见操作系统资源提供托管包装类是 Microsoft 的工作。像 FileStream、Socket 等。这些类几乎总是实现 IDisposable。当您将此类对象存储在自己的类中时,您在代码中唯一需要做的就是自己实现 IDisposable,这样您就可以在这些对象上调用 Dispose() 方法。或者,如果您将它们用作方法中的局部变量,请使用using语句。

于 2012-12-09T15:22:46.757 回答
1

在这种情况下,将“资源”理解为“一个对象要求其他人代表它做的事情,直到另行通知,这会损害其他所有人”是最有帮助的。如果放弃一个对象会导致垃圾收集器通知该对象放弃,并且该对象反过来指示代表它行事的任何事物停止这样做,则该对象构成“托管资源”。“非托管资源”是未封装在托管资源中的资源。

如果某个对象Foo为非托管内存分配了句柄,它会要求内存管理器授予它对某个内存区域的独占使用权,使其对任何其他可能想要使用它的代码不可用,直到Foo通知内存管理器不再需要内存,因此应将其用于其他目的。使句柄成为非托管资源的原因不是它是通过 API 接收的,而是即使放弃了对它的所有故意引用,内存管理器也会永远继续将内存的独占使用权授予一个没有不再需要它(并且可能不再存在)。

虽然 API 句柄是最常见的非托管资源类型,但还有无数其他类型。诸如监视器锁和事件之类的东西完全存在于 .net 的托管代码世界中,但仍然可以表示非托管资源,因为获取锁并在代码等待它时放弃可能会导致该代码永远等待,并且由于短暂的从长寿命对象订阅事件并且在被放弃之前未能取消订阅的对象可能会导致该长寿命对象无限期地继续携带事件引用(如果只放弃一个订阅者,这是一个小负担,但一个无限的负担如果创建和放弃了无限数量的订阅者)。

附录 垃圾收集器的一个基本假设是,当对象 X 持有对对象 Y 的引用时,这是因为 X 对 Y“感兴趣”。然而,在某些情况下,可能持有该引用是因为 X 希望 Y 持有一个引用即使 Y 不以某种方式“关心”它。这种情况在通知事件处理程序中经常发生。每次对象 X 发生某些事情时,对象 Y 可能希望得到通知。尽管 X 必须保留对 Y 的引用以便执行此类通知,但 X 本身并不关心通知。它只执行它们是因为假设某些根对象可能关心 Y 接收它们。

在某些情况下,可以使用所谓的“弱事件模式”。不幸的是,虽然 .net 中有许多弱事件模式,但由于缺乏适当的WeakDelegate类型,它们都有一些怪癖和限制。此外,虽然弱事件是有帮助的,但它们并不是灵丹妙药。假设,例如,当发生某事时,它Y要求长寿命对象X通知它,唯一现有的引用YX用于此类通知的引用,此类通知的唯一Y作用是增加某个 object 中的属性Z,并且设置该属性不会修改任何外部Z。在这种情况下,即使 objectZ将是宇宙中唯一“关心” object 的事物YZ不会持有任何类型的引用Y,因此垃圾收集器将无法将Y的生命周期与Z. 如果 aX持有对 的强引用Y,即使没有人对它感兴趣,后者也会保持活动状态。如果X只持有一个弱引用,那么Y即使Z对它感兴趣也可能被垃圾收集。没有机制可以让垃圾收集器自动推断出ZY.

于 2012-12-10T21:36:08.290 回答