我正在阅读Wrox 的 Professional C# 4 and .NET 4关于“内存管理和指针”一章,特别是关于垃圾收集在 .NET 中的工作方式。它说“垃圾收集器不知道如何释放非托管资源(例如文件句柄、网络连接和数据库连接)”的原因,这就是为什么这些类应该声明析构函数(又名“终结器”)或实现IDisposable
.
似乎所有这些“非托管资源”示例都与与应用程序外部且独立于 .NET Framework 的系统的交互有关。但是,我不确定这是否是完全的区别,所以,
我正在阅读Wrox 的 Professional C# 4 and .NET 4关于“内存管理和指针”一章,特别是关于垃圾收集在 .NET 中的工作方式。它说“垃圾收集器不知道如何释放非托管资源(例如文件句柄、网络连接和数据库连接)”的原因,这就是为什么这些类应该声明析构函数(又名“终结器”)或实现IDisposable
.
似乎所有这些“非托管资源”示例都与与应用程序外部且独立于 .NET Framework 的系统的交互有关。但是,我不确定这是否是完全的区别,所以,
你没看错:
托管资源由 CLR 管理,非托管资源不是。换句话说:托管资源仅存在于 .NET 世界中,而非托管资源来自正常的 Win32 世界。
使用托管资源(即内存),您不必担心使用完它们后会发生什么;CLR 会处理这个问题。
非托管资源(有几种类型:Windows 内核对象、GDI 对象、USER 对象)在您使用完它们后必须释放回系统。当您的进程终止时,这会自动发生,但是如果它同时泄漏它们,您就会遇到一个大问题,因为您正在泄漏系统中所有进程之间共享的资源。
当然,.NET 中有几个类可以包装这些非托管资源(使用dispose/finalize 模式)并为您完成艰苦的工作。如果可以,请使用它们。
我会说通常使用 .Net 框架创建的任何东西都是托管资源。在内部,它们可能使用非托管资源,但从您的角度来看,它们是托管的。例外情况之一是当您 P/Invoke 时。尽管您创建了一个与 .Net 一起使用的函数,但调用会在 .Net“沙盒”之外传递,因此被认为是非托管的。
回复@supercat
来自长生命周期对象的事件可能完全在 .net 框架内处理,但它们肯定需要被视为非托管资源以防止内存泄漏
我认为这里有两件不同的事情。有托管与非托管的讨论,还有应用程序的内存管理的讨论。您可能应该将某些对象视为非托管对象,但这并不意味着它们是非托管对象。例如,Brush
我认为是托管的类,但您应该通过调用将其视为非托管类Dispose()
。在类中隐藏/抽象的是您希望Dispose()
处理的非托管对象。但Dispose()
实际上并没有释放任何资源,它只是您希望开发人员正确实施的一种模式。
更进一步,我想说大多数非托管对象是通过调用CreateXYZ()
返回指针的 Win32 方法创建的,但需要使用采用相同指针的“DestroyXYZ()/DeleteXYZ()”方法来释放。另一方面,托管对象实现 Dispose/Finalize 来为您执行此操作。再一次,您希望托管资源的编写者已经这样做了,但不能保证。
“非托管资源”一词令人困惑。一个更有用的概念是“清理责任”。如果一个对象拥有非托管资源,这意味着三件事:
通常,术语“托管资源”用于指持有非托管资源的对象,但如果发现它们被丢弃,它们将从垃圾收集器(通过 Finalize 例程)接收通知,并且将使用此类通知提供清理(以防他们在调用正常清理方法之前被放弃)。有些人使用术语“托管资源”来指代不需要任何清理的东西,但我不喜欢这样的用法,因为没有任何其他好的术语来指代应该手动清理的东西,但是如果没有发生正常的清理,将使用 finalization 作为后备。
请注意,虽然非托管资源通常是诸如文件的操作系统句柄、GDI 实体等之类的东西,但以这样的术语来考虑它们是错误的。可能有非托管资源无法访问 .Net 框架之外的任何内容;事件处理程序就是一个常见的例子。非托管资源的关键方面是它们需要清理,而未能执行此类清理将产生一些不良后果。