我正在阅读有关如何实现IDisposable的MSDN文章,但是我对文章中提到的托管资源和本机资源之间的区别感到不确定。
我有一个类,在被处理时必须处理其中的两个字段。我应该将它们视为托管资源(仅在disposing = true时进行处理)还是本机资源?
我正在阅读有关如何实现IDisposable的MSDN文章,但是我对文章中提到的托管资源和本机资源之间的区别感到不确定。
我有一个类,在被处理时必须处理其中的两个字段。我应该将它们视为托管资源(仅在disposing = true时进行处理)还是本机资源?
补充Brian的回答和您的评论/问题:
托管/非托管资源之间的区别在于垃圾回收器(Garbage Collector)知道托管资源但不知道非托管资源。我知道这个回答不是很具体,但是这个区别非常重要。
为了帮助划清界限,以下是GC运行和清理内存的简短版本(可能有些错误):
垃圾收集器知道所有托管对象,但当垃圾回收运行时,它起初不知道任何给定的对象是否仍在使用或是否可以释放。它通过将所有对象标记为垃圾来确定是否可以清理对象,然后从应用程序根到所有引用的对象进行遍历。每个具有与根(直接或间接)的关系的对象都被标记为可达,并且不再被视为垃圾。在GC遍历每个可达对象后,它会清理其余未使用的对象。
在几乎所有的情况下,使用.NET框架对象时,您可以确信对象是托管的(.NET提供了几乎所有非托管资源的托管封装,以确保它们被正确清理);其他第三方组件也可能连接到Win32 API(或者您的组件这样做),这些对象可能会引起关注。
有一些.NET对象可以被认为是非常不可管理的,Graphics库的组件就是一个例子。
大多数“.NET内存泄漏”实际上并不是真正的内存泄漏。通常发生在您认为已经从使用中删除了一个对象,但实际上该对象仍然与应用程序有某种引用。常见的例子是添加事件处理程序( obj.SomeEvent += OnSomeEvent 或者AddHandler obj.SomeEvent, AddressOf OnSomeEvent )但没有将它们删除。
这些“残留引用”在技术上不算是内存泄漏,因为您的应用程序仍然在使用它们;但是如果有足够多的这些引用,您的应用程序可能会受到严重的性能影响,并可能显示出资源问题(OutOfMemoryExceptions、无法获取窗口句柄等)。
我是一名中级的.NET开发者,不幸地亲自遇到过这些问题。我建议使用ANTS Profiler来帮助熟悉残留引用(有一个免费试用版),或者如果你想进行更深入的研究,可以使用WinDbg和SOS.DLL来查看托管堆。如果你决定研究后者,我建议阅读Tess Ferrandez的博客;她有很多关于有效使用Windbg的教程和建议。
被管理的资源是另一种实现了IDisposable
接口的托管类型。您需要在使用任何其他IDisposable
类型时调用Dispose()
方法。本地资源是托管世界之外的任何东西,例如本地Windows句柄等。
编辑: 回答评论中的问题(过长无法作为评论)
不是,那只是一种托管类型。正确构造的类型,没有实现IDisposable
接口将由垃圾回收器处理,您不必做其他任何事情。如果您的类型直接使用本地资源(例如通过调用Win32库),则必须在类型上实现IDisposable
接口,并在Dispose
方法中释放资源。如果您的类型使用由另一个实现IDisposable
接口的类型封装的本机资源,则必须在您的类型的Dispose
方法中调用此类型的实例上的Dispose()
方法。
简短的回答是,任何你绕过CLR(到操作系统)获取的内容都可以称为“本地”。
因此,现在CantStayManaged有两件事情需要清理才能告别。
现在有两种方法可以触发对象清理。
if (AmIBeingCalledFromDispose)
保护检查来保护你的托管清理,可以避免出现问题。