究竟什么是非托管资源?

Dev*_*Das 148 c# unmanaged

我想知道非托管资源.任何人都可以给我一个基本的想法吗?

And*_*ell 165

托管资源基本上是指由垃圾收集器管理的"托管内存".当您不再对托管对象(使用托管内存)进行任何引用时,垃圾收集器将(最终)为您释放该内存.

然后,非托管资源就是垃圾收集器不知道的所有内容.例如:

  • 打开文件
  • 打开网络连接
  • 非托管内存
  • 在XNA中:顶点缓冲区,索引缓冲区,纹理等.

通常,您希望丢失对管理它们的对象的所有引用之前释放这些非托管资源.你可以通过调用Dispose该对象或(在C#中)使用using将处理调用的语句来完成此操作Dispose.

如果您Dispose正确地忽略了非托管资源,当包含该资源的对象被垃圾收集时(这是"终结"),垃圾收集器最终将为您处理它.但是因为垃圾收集器不知道非托管资源,所以它无法分析释放它们需要多么糟糕 - 所以你的程序可能表现不佳或完全耗尽资源.

如果您自己实现一个处理非托管资源的类,则由您来实现DisposeFinalize正确实现.

  • @ganders这是一个很好的经验法则.但请注意,所有C#类实例都是托管对象.如果类**的实例可以**持有非托管资源,那么该类**应该实现`IDisposable`.如果一个类**实现了`IDisposable`,那么当你完成它们时,你应该用`using`或`Dispose()`来处理该类的实例.基于此,你的反过来认为:如果一个类实现了`IDisposable`,那么它****可能**在内部保存非托管资源. (15认同)
  • 我对此有一个基本的评论/问题,我可以将对象关联为仅由类型管理/取消管理,例如,字符串是托管的,DataSet是非托管的(这就是为什么它有Dispose()方法) ,数据库连接是不受管理的(因为它们已经处置),等等.假设,如果它有一个"Dispose()"方法,那么它是不受管理的?除此之外,XmlDocument对象是什么?谢谢 (11认同)
  • +1其他答案错过了你在一个*managed*对象上调用Dispose的重要一点,该对象在内部处理它所包装的非托管资源的释放(例如文件句柄,GDI +位图,......),如果你访问非托管资源直接(PInvoke等)你需要处理. (7认同)
  • 开放数据库连接属于哪个类别?托管/非托管? (5认同)
  • @Dev:Unmanaged - 因为GC不知道它(假设您没有使用某些假设的托管内存数据库).但是连接对象*本身*可能不包含非托管资源.据推测,数据库连接使用打开的文件或网络连接*某处* - 但*可能*另一个对象(连接对象除外)正在处理该非托管资源(可能是您的数据库库缓存连接).检查文档并查看它要求您调用`Dispose`或使用`using`. (2认同)

Mar*_*tas 47

一些用户对托管资源中的打开文件,数据库连接,分配的内存,位图,文件流等进行排名,其他用户在非托管资源中进行排名.那么他们是管理还是不管理?

我的观点是,响应更复杂:当你在.NET中打开文件时,你可能会使用一些内置的.NET类System.IO.File,FileStream或其他东西.因为它是一个普通的.NET类,所以它是受管理的.但它是一个包装器,它内部执行"脏工作"(使用Win32 dll与操作系统通信,调用低级函数甚至汇编指令),它们真正打开文件.这就是.NET不知道的,没有管理的.但您可以使用汇编程序指令自行打开文件并绕过.NET文件函数.然后句柄和打开的文件是非托管资源.

与DB相同:如果您使用某些数据库程序集,则您拥有类似DbConnection等的类,它们已为.NET所知并受到管理.但它们包装了"脏工作",这是不受管理的(在服务器上分配内存,与它建立连接,......).如果您不使用此包装类并自行打开某个网络套接字并使用某些命令与您自己的奇怪数据库进行通信,则它是不受管理的.

这些包装类(File,DbConnection等)是受管理的,但它们内部使用非托管资源的方式与您相同,如果您不使用包装器并自己执行"脏工作".因此这些包装器实现Dispose/Finalize模式.他们有责任让程序员在不再需要包装器时释放非托管资源,并在包装​​器被垃圾收集时释放它们.包装器将被垃圾收集器正确地垃圾收集,但是内部的非托管资源将通过使用Dispose/Finalize模式来收集.

如果您没有在类中使用内置的.NET或第三方包装类并通过某些汇编程序指令打开文件,则这些打开的文件是不受管理的,您必须实现dispose/finalize模式.如果不这样做,即使您不再使用它(文件操作完成),甚至在应用程序终止后,也会出现内存泄漏,永久锁定的资源等.

但是你在使用这些包装时也有责任.对于那些实现dispose/finalize(你认识到它们实现了IDisposable)的人,还要实现你的dispose/finalize模式和Dispose甚至这些包装器或给它们发出信号以释放它们的非托管资源.如果不这样做,资源将在一段时间内无限期释放,但是立即释放它是干净的(立即关闭文件,不要让它打开并随机几分钟/小时随机阻止).因此,在您的类的Dispose方法中,您可以调用所有使用过的包装器的Dispose方法.

  • 很好地进一步明确了“非托管资源与托管资源” (2认同)
  • 这很简单。在使用的每个类上,必须验证它是否实现IDisposable接口。如果是,那么,如果您在一种方法中使用了此类(例如:打开文件,存储文本,关闭文件),则可以使用using(){}模式,该模式会自动为您调用Dispose。如果您在更多方法中使用此类(例如:您的类包含File,在构造函数中打开文件,然后几个方法添加一些日志...),那么您必须通过类实现IDisposable接口,实现Dispose / Finalize模式并正确处置该类的对象。 (2认同)

Dav*_*vid 12

非托管资源是那些在.NET运行时(CLR)之外运行的资源(也就是非.NET代码.)例如,在Win32 API中调用DLL,或者用C++编写的.dll调用.


Mar*_*rko 5

托管和非托管资源之间的基本区别在于垃圾收集器知道所有托管资源,在某个时间点GC将出现并清理与托管对象关联的所有内存和资源.GC不知道非托管资源,例如文件,流和句柄,因此如果您不在代码中明确清除它们,那么最终会导致内存泄漏和锁定资源.

这里被盗,随时阅读整篇文章.


sup*_*cat 5

"非托管资源"不是一件事,而是一种责任.如果一个对象拥有一个非托管资源,这意味着(1)它之外的某个实体被操纵的方式可能会导致问题,如果不清理,和(2)该对象具有执行此类清理所需的信息并负责这样做.

虽然许多类型的非托管资源与各种类型的操作系统实体(文件,GDI句柄,分配的内存块等)密切相关,但除了责任之外,没有任何单一类型的实体由所有这些实体共享.清理.通常,如果一个对象有责任执行清理,它将有一个Dispose方法,指示它执行它负责的所有清理.

在某些情况下,对象会考虑在没有任何人先调用Dispose的情况下放弃它们的可能性.GC允许对象请求通知它们已被放弃(通过调用名为Finalize的例程),对象可以使用此通知自行执行清理.

不幸的是,"托管资源"和"非托管资源"等术语被不同的人用来表示不同的东西; 坦率地认为,根据对象来考虑更有用,要么没有任何清理责任,只有在调用Dispose时才会负责清理责任,或者需要通过Dispose处理清理责任,但哪些可以也可以通过Finalize来处理.