什么算作一次性模式中的“非托管资源”?

时间:2012-03-30 19:36:26

标签: .net

我正在使用此处描述的模式来管理处置: http://www.developerzen.com/2006/01/09/finalizableobject-developing-a-base-class-for-idisposable-objects/

什么算作“非托管资源?”

以下是我脑海中的一些令人困惑的问题:

  • 在某些时候,.NET只是包装Win32调用,对吧?因此,大多数.NET对象都不是非托管资源吗?
  • 我们有.NET包装器的COM对象怎么样 - 他们考虑了什么?
  • 那些只从P / Invokes获得功能的托管类呢?
  • 内部使用本机库的C ++ / CLI类怎么样?在C#级别,具有析构函数的C ++ / CLI类现在实现了IDisposable ......他们考虑了什么?

我意识到博客文章有点陈旧。如果有更现代的方法来管理非托管和托管对象的生命周期,请提出建议。

编辑:无论谁投票结束此事,请提供一些有关如何改进问题的详细信息。

3 个答案:

答案 0 :(得分:7)

我理解这种困惑。我认为有一些简单的指导方针可供遵循:

  1. 如果你的类“拥有”对另一个对象的引用(即你的对象创建了另一个对象,或者在得知你的对象现在“拥有”它的情况下被赋予对该对象的引用),那么你就是负责进行任何必要的清理(如果有的话)

  2. 如果该其他对象是.NET对象并且未实现IDisposable接口,那么您可能不需要执行任何操作。按照惯例,IDisposable接口是我们用来声明我们的对象是否需要清理的接口。

  3. 如果该另一个对象是.NET对象并实现了IDisposable接口,那么您的类也应该实现IDisposable接口。在Dispose方法中,只需调用另一个对象的Dispose方法。

  4. 如果该其他对象是非托管对象或资源,那么您的类应该实现终结器以确保将清除非托管对象/资源。请遵循该博客文章中描述的指南,了解如何实现该目标。

  5. 以下是您问题的一些具体答案。

      
        
    • 在某些时候,.NET只是包装Win32调用,对吧?因此,大多数.NET对象都不是非托管资源吗?
    •   

    即使.NET对象可能包装Win32调用,术语“非托管资源”也不合适,因为它是.NET对象,因此根据定义它是“托管资源”。 CLR处理这些对象的内存分配和垃圾收集。

      
        
    • 我们有.NET包装器的COM对象怎么样 - 他们考虑了什么?
    •   

    .NET包装器对象仍然是.NET对象,因此它们是“托管资源”,但请注意它们必须实现自己的dispose / finalize逻辑。基本上,他们负责清理“非托管资源”,以便您不必这样做。如果您正在为COM对象实现自己的包装器,那么您将负责实现必要的dispose / finalize逻辑来清理它,以便包装器的使用者不必这样做。

      
        
    • 那些仅通过P / Invokes获得功能的托管类呢?
    •   

    使用P / Invoke调用非托管代码的托管类可能正在分配非托管资源,具体取决于它调用的内容。因此,它可能需要实现必要的dispose / finalize逻辑来清理那些非托管资源。

      
        
    • 内部使用本机库的C ++ / CLI类怎么样?
    •   

    是的,那些也可能是从本机库分配非托管资源,因此他们也有必要实现必要的析构函数/终结器逻辑。

      
        
    • 在C#级别,具有析构函数的C ++ / CLI类现在实现了IDisposable ......他们考虑了什么?
    •   

    在C ++ / CLI中,您可以选择将类声明为managed(使用ref关键字)或unmanaged(不使用ref关键字)。如果使用ref关键字声明它,那么它是一个托管类;它将在托管堆上分配,并且一旦它超出范围就会被垃圾收集器清理,并且不再有对它的引用。如果声明的类没有ref关键字,那么它是非托管的,必须明确清理。在任何一种情况下,类都可能已经分配了需要在析构函数/终结器中清理的非托管资源。

答案 1 :(得分:1)

以下是我视为“非托管”的内容(请注意引号):

  1. 任何实现IDisposable的东西。如果它想被处置......好吧,相信它。它是纯粹的“安全”.NET还是实现一个空的Dispose方法并不重要。为了使用Disposable模式处理它,它是“非托管”。
  2. 任何COM RCW。对此有很多争论; I view each COM->NET RCW count-increase as "owned" and thus "unmanaged"最终 RCW会在析构函数中清理自己,但在处理Outlook对象模型时“最终”会导致很多问题,这就是我的工作。这种方法需要一致的方法来处理COM对象和生命周期,以避免“RCW分离”问题。
  3. 通过P / Invoke调用(例如BSTR)获得的任何[new] 资源:分配所述资源的东西“拥有”它直到放弃控制。这确实是一个“非托管”资源,必须发布。可以分配的各种资源有一些有用的包装类型。
  4. 我不处理非COM本机代码(例如CLI),除了几个WinAPI调用,它们都是C。

答案 2 :(得分:0)

首先想到的是,.net之外的任何东西都是非托管资源。托管对象是.net字符串,数组,值类型和由它们组成的复杂类型,所有这些都是托管的,其生命周期由.net自动控制。 String不是一个包装器,所以它是完全管理的。

大多数.net基类都是从头开始编写的,比如List,Stack等。我们可以通过说任何对象和它的后代仅引用堆栈中的数据或堆管理来简化。

任何其他打开的连接/句柄来访问堆栈/堆外的任何内容都是不受管理的,无论是文件,命名管道,网络还是任何设备。

大多数其他BCL类都经过优化,但除非你使用块包装它们,否则它们不会以它们被编写的方式自动处理。