简体   繁体   English

处理时托管资源和本机资源有什么区别? (。净)

[英]What is the difference between managed and native resources when disposing? (.NET)

I was reading the MSDN article about how to implement IDisposable and I am uncertain about the difference between managed and native resources cited in the article. 我正在阅读有关如何实现IDisposableMSDN文章 ,我不确定文章中引用的托管和本机资源之间的区别。

I have a class that must dispose 2 of its fields when it is disposed. 我有一个类在处理它时必须处理它的两个字段。 Should I treat them as Managed (dispose only when disposing = true) or Native resources? 我应该将它们视为托管(仅在处置= true时处置)或本机资源吗?

To add a little to Brian's answer, and your comment/question: 为Brian的回答添加一点,以及您的评论/问题:

The difference between a Managed/Unmanaged resource is that the Garbage Collector is aware of managed resources and isn't aware of unmanaged resources. 托管/非托管资源之间的区别在于垃圾收集器了解托管资源,并且不知道非托管资源。 I know that answer isn't very concrete but the difference is huge. 我知道答案不是很具体,但差别很大。

To help draw the line in the sand here is the short (and probably riddled with little errors) version of how GC runs and cleans up memory: 为了帮助在这里绘制线条,这是GC运行和清理内存的简短版本(可能还有很少的错误):

The garbage collector is aware of all managed objects but when garbage collection runs it doesn't initially know if any given object is still in use or is elegible to be released. 垃圾收集器知道所有托管对象,但是当垃圾收集运行时,它最初不知道任何给定对象是否仍在使用中或者是否可以被释放。 It determines whether or not it can cleanup an object by initially marking all objects as garbage, then traversing from the application root to all referenced objects. 它通过最初将所有对象标记为垃圾,然后从应用程序根遍历到所有引用的对象来确定它是否可以清理对象。 Each object that has a relationship back to the root (a reference, either direct or indirect) gets marked as reachable and is no longer considered garbage. 具有回到根的关系的每个对象(引用,直接或间接)被标记为可达,并且不再被视为垃圾。 After the GC runs through every reachable object it cleans up the rest since they are no longer in use. GC运行通过每个可到达的对象后,它会清理其余的,因为它们不再使用。

In almost all cases working with .NET framework objects you can be assured that objects are managed (.NET provides managed wrappers of nearly all unmanaged resources to ensure they are properly cleaned up); 几乎在所有使用.NET框架对象的情况下,都可以确保管理对象(.NET提供几乎所有非托管资源的托管包装,以确保它们得到正确清理); other third party components which hook into the Win32 API (or your components which do this) are the objects which may be cause for concern. 挂钩到Win32 API(或执行此操作的组件)的其他第三方组件是可能引起关注的对象。

There are some .NET objects which can be considered to be somewhat unmanaged. 有些.NET对象可以被认为是有些不受管理的。 Components of the Graphics library are one example. 图形库的组件就是一个例子。

Most ".NET Memory leaks" aren't really memory leaks in the true sense. 大多数“.NET内存泄漏”并不是真正意义上的内存泄漏。 Typically they occur when you think you have removed an object from use but in fact the object still has some reference to the application. 通常,当您认为已从使用中删除了某个对象时,它们就会出现,但实际上该对象仍然具有对该应用程序的一些引用。 A common example is adding eventhandlers (obj.SomeEvent += OnSomeEvent -or- AddHandler obj.SomeEvent, AddressOf OnSomeEvent) and not removing them. 一个常见的例子是添加eventhandler(obj.SomeEvent + = OnSomeEvent -or- AddHandler obj.SomeEvent,AddressOf OnSomeEvent)而不删除它们。

These 'lingering references' are technically not memory leaks since your application is still technically using them; 这些“挥之不去的引用”在技术上并不是内存泄漏,因为您的应用程序仍在技术上使用它们; however if there are enough of them your application can suffer severe performance impacts and may show signs of resource issues (OutOfMemoryExceptions, unable to attain window handles, etc). 但是,如果有足够的应用程序,您的应用程序可能会受到严重的性能影响,并可能显示资源问题的迹象(OutOfMemoryExceptions,无法获得窗口句柄等)。

I'm an intermediate .NET developer and unfortunately know about these problems first-hand. 我是一名中级.NET开发人员,不幸的是他第一时间了解这些问题。 I recommend playing with ANTS Profiler to help become familiar with lingering references (there is a free trial version) or if you want to get a little bit more nitty-gritty research using WinDbg and SOS.DLL to look at the managed heap. 我建议使用ANTS Profiler来帮助熟悉延迟引用(有一个免费试用版),或者如果你想通过WinDbg和SOS.DLL来查看托管堆,可以进行更多细节研究。 If you decide to look into the latter I recommend reading Tess Ferrandez' blog; 如果您决定研究后者,我建议您阅读Tess Ferrandez的博客; she has a lot of great tutorials and advice on using Windbg effectively 她有很多关于有效使用Windbg的精彩教程和建议

A managed resource is another managed type, which implements IDisposable . 托管资源是另一种托管类型,它实现了IDisposable You need to call Dispose() on any other IDisposable type you use. 您需要在您使用的任何其他IDisposable类型上调用Dispose() Native resources are anything outside the managed world such as native Windows handles etc. 本机资源是托管世界之外的任何内容,例如本机Windows句柄等。


EDIT : Answer to question in comment (too long for comment) 编辑 :回答评论中的问题(评论太长)

No that is just a managed type. 不,这只是一种托管类型。 A correctly constructed type, which doesn't implement IDisposable will be handled by the garbage collector and you don't have to do anything else. 正确构造的类型(不实现IDisposable将由垃圾收集器处理,您不必执行任何其他操作。 If your type uses a native resource directly (eg by calling Win32 libraries), you must implement IDisposable on your type and dispose of the resource(s) in the Dispose method. 如果您的类型直接使用本机资源(例如,通过调用Win32库),则必须在类型上实现IDisposable并在Dispose方法中处置资源。 If your type uses a native resource encapsulated by another type which implements IDisposable , you must call Dispose() on instances of this type in the Dispose method of your type. 如果您的类型使用由实现IDisposable的另一种类型封装的本机资源,则必须在类型的Dispose方法中对此类型的实例调用Dispose()

The short answer would be anything that you go behind the CLR's back (to the OS) to obtain can be termed as ' native '. 简短的回答是你在CLR背后(到操作系统)获得的任何东西都可以被称为“ 原生 ”。

  • unmanaged memory allocation. 非托管内存分配。 If you 'new' up a chunk of memory in a managed class CantStayManaged, then CantStayManaged is responsible for freeing this memory (resource). 如果你在托管类CantStayManaged中“新”了一大块内存,那么CantStayManaged负责释放这个内存(资源)。
  • handles to files, pipes, events, synchronization constructs, etc. - as a thumb rule if you call WinAPIs to obtain pointers/handles to a resource, then those are 'native resources' 处理文件,管道,事件,同步构造等 - 作为一个拇指规则,如果你调用WinAPIs来获取资源的指针/句柄,那么这些是“本机资源”

So now CantStayManaged has 2 things it needs to cleanup before it bids adieu. 所以现在CantStayManaged在它出价之前需要清理2件事。

  1. Managed: Member fields and any resources the CLR allocated. 托管:成员字段和CLR分配的任何资源。 This usually equates to calling Dispose on your 'Disposable' member objects. 这通常等同于在“Disposable”成员对象上调用Dispose。
  2. Unmanaged: all the sneaky low-level stuff we pull behind its back. 不受管理:我们背后隐藏着所有偷偷摸摸的低级别东西。

There are 2 ways the object cleanup can be triggered now. 现在有两种方法可以触发对象清理。

  1. Dispose(true) case: You called Dispose explicitly on your type. Dispose(true)case:您在类型上显式调用Dispose。 Good programmer. 优秀的程序员。
  2. Dispose(false) case: You forgot to call Dispose, in which case the finalizer should kick in and still ensure proper cleanup. Dispose(false)case:你忘了调用Dispose,在这种情况下终结器应该启动并仍然确保正确清理。

In both cases, the unmanaged resources should be freed up else 'LEAKS!', 'CRASHES!' 在这两种情况下,非托管资源应该被释放,否则“泄漏!”,“崩溃!” et.all surface. 等表面。 But you should only attempt to cleanup managed resources only in Dispose() former case. 但是,您应该只尝试在Dispose()以前的情况下清理托管资源。 In the latter/finalizer case - the CLR might have already finalized and collected some of your members, so you shouldn't access them (CLR doesn't guarantee an order in which an object graph is finalized.) Hence you avoid issues by guarding your managed cleanup with an if (AmIBeingCalledFromDispose) guard check 在后者/终结器的情况下 - CLR可能已经完成并收集了一些成员,因此您不应该访问它们(CLR不保证最终确定对象图的顺序。)因此,您可以避免出现问题使用if (AmIBeingCalledFromDispose)保护检查进行托管清理

HTH HTH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM