确定托管与非托管资源

时间:2012-12-09 10:18:21

标签: c# .net resources idisposable

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

当我想到非托管资源时,我倾向于考虑不直接属于.NET的本机代码,例如pinvoke或编组资源。我通常认为资源意味着与使用硬件的东西接口,例如文件句柄或网络连接也是不受管理的。

如何包装本地非托管资源的.NET对象,例如FileStream

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

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

3 个答案:

答案 0 :(得分:14)

  

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

FileStream是托管资源

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

  

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

正确。

  

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

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

答案 1 :(得分:10)

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

如果您使用记录不良的库,那么当您恢复IntPtr时请注意。这是一个非常强烈的迹象,表明涉及非托管分配,指向非托管内存或操作系统句柄。那么该库也应该为您提供一种释放它的方法,如果它没有自动管理它。如果您不确定如何妥善处理,请联系图书馆的所有者。

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

答案 2 :(得分:1)

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

如果某个对象Foo为非托管内存分配句柄,它会要求内存管理器授予它对某些内存区域的独占使用权,使其无法使用其他任何可能需要使用它的代码,直到这样的时间Foo通知内存管理器不再需要内存,因此应该可以用于其他目的。使句柄成为非托管资源的原因不在于它是通过API接收的,而是即使所有故意引用它都被放弃的事实,内存管理器将永远继续授予对象的独占使用权。需要更长时间(可能不再存在)。

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

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

在某些情况下,可以使用所谓的“弱事件模式”。不幸的是,虽然.net中存在许多弱事件模式,但由于缺少适当的WeakDelegate类型,它们都存在怪癖和局限性。此外,虽然弱事件是有帮助的,但它们不是灵丹妙药。例如,假设Y已经要求长期存在的对象X在发生某些事情时通知它,Y唯一的现有引用是X用于此类的Y通知,Z对此类通知的唯一作用是增加某个对象Z中的属性,并且该属性在Z之外修改该属性。在这种情况下,即使对象Y是宇宙中唯一“关心”对象Z的东西,Y也不会对Y进行任何形式的引用无论如何,所以垃圾收集器无法将Z的生命周期与X的生命周期联系起来。如果Y拥有X的强引用,即使没有人对此感兴趣,后者也会保持活跃状态​​。如果Y仅包含弱引用,则即使Z对其感兴趣,Z也可能被垃圾收集。垃圾收集器没有机制可以自动推断Y对{{1}}感兴趣。