究竟什么是非托管资源?

时间:2010-08-08 05:24:15

标签: c# unmanaged

我想了解非托管资源。 任何人都可以给我一个基本的想法吗?

8 个答案:

答案 0 :(得分:155)

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

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

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

通常,您希望在之前释放那些非托管资源,您将失去对管理它们的对象的所有引用。您可以通过调用该对象上的Dispose或使用using语句调用(在C#中)来执行此操作,该语句将为您处理调用Dispose

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

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

答案 1 :(得分:42)

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

我的观点是,响应更复杂:当你在.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 :(得分:11)

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

答案 3 :(得分:5)

托管和非托管资源之间的基本区别在于 垃圾收集器在某个时间点知道所有托管资源 GC将出现并清理所有相关的内存和资源 使用托管对象。 GC不知道非托管资源 作为文件,流和句柄,所以如果你没有明确地清理它们 你的代码然后你将最终导致内存泄漏和锁定的资源。

here被盗,随时阅读整个帖子。

答案 4 :(得分:5)

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

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

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

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

答案 5 :(得分:1)

在.NET托管堆中为其分配内存的任何资源都是托管资源。 CLR完全了解这种内存并将尽一切努力确保它不会成为孤儿。其他任何东西都是不受管理的。例如,与COM进行交互,可能会在进程内存空间中创建对象,但CLR不会处理它。在这种情况下,跨托管边界进行调用的托管对象应该对超出它的任何内容负责。

答案 6 :(得分:0)

让我们首先了解VB6或C ++程序(非Dotnet应用程序)如何执行。 我们知道计算机只能理解机器级代码。机器级代码也称为本机代码或二进制代码。因此,当我们执行VB6或C ++程序时,相应的语言编译器将相应的语言源代码编译为本机代码,然后可以由底层操作系统和硬件理解。

本机代码(非托管代码)是生成它的操作系统的特定(本机)。如果您使用此编译的本机代码并尝试在另一个操作系统上运行它将失败。因此,这种程序执行方式的问题在于,它无法从一个平台移植到另一个平台。

现在让我们了解一下.Net程序是如何执行的。使用dotnet我们可以创建不同类型的应用程序。一些常见类型的.NET应用程序包括Web,Windows,控制台和移动应用程序。无论应用程序的类型如何,当您执行任何.NET应用程序时,都会发生以下情况

  1. .NET应用程序被编译为中级语言(IL)。 IL也称为通用中间语言(CIL)和Microsoft中间语言(MSIL)。 .NET和非.NET应用程序都生成程序集。程序集的扩展名为.DLL或.EXE。例如,如果您编译Windows或控制台应用程序,则会得到.EXE,在编译Web或类库项目时,我们会得到.DLL。 .NET和NON .NET程序集之间的区别在于,DOTNET程序集采用中间语言格式,其中NON DOTNET程序集采用本机代码格式。

  2. NON DOTNET应用程序可以直接在操作系统之上运行,其中DOTNET应用程序在称为公共语言运行时(CLR)的虚拟环境之上运行。 CLR包含一个名为Just In-Time Compiler(JIT)的组件,它将中间语言转换为底层操作系统可以理解的本机代码。

  3. 因此,在.NET中,应用程序执行包含两个步骤 1.语言编译器,将源代码编译成中间语言(IL) 2. CLR中的JIT编译器将IL转换为本机代码,然后可以在底层操作系统上运行。

    因为.NET程序集是Intermedaite语言格式而不是本机代码,所以只要目标平台具有公共语言运行时(CLR),.NET程序集就可以移植到任何平台。目标平台的CLR将Intermedaite语言转换为底层操作系统可以理解的本机代码。 Intermediate Languge也称为托管代码。这是因为CLR管理在其中运行的代码。例如,在VB6程序中,开发人员负责取消分配对象所消耗的内存。如果程序员忘记取消分配内存,我们可能会遇到很难检测内存不足的异常。另一方面,.NET程序员不必担心取消分配对象消耗的内存。 CLR提供自动内存管理,也称为垃圾收集。除了垃圾收集之外,CLR还提供了其他一些好处,我们将在稍后的会议中讨论。由于CLR正在管理和执行中间语言,因此它(IL)也称为托管代码。

    .NET支持不同的编程语言,如C#,VB,J#和C ++。 C#,VB和J#只能生成托管代码(IL),因为C ++可以生成托管代码(IL)和非托管代码(本机代码)。

    本机代码不会永久存储在任何地方,在我们关闭程序后,本机代码将被抛弃。当我们再次执行程序时,将再次生成本机代码。

    .NET程序类似于java程序执行。在java中我们有字节码和JVM(Java虚拟机),在.NET中我们使用中间语言和CLR(公共语言运行时)

    这是从这个链接提供的 - 他是一个很棒的导师。 http://csharp-video-tutorials.blogspot.in/2012/07/net-program-execution-part-1.html

答案 7 :(得分:0)

非托管和托管资源基于 application domain

据我所知,非托管资源是用于连接到 outside of your application domain 的一切。 您可以使用 HttpClient 类来获取域外的数据,也可以使用 FileStream 类来帮助您从/向文件读/写。

我们在工作完成后立即使用 Using 块来处理这些类对象,因为 GC 首先关心进程内部的资源而不是外部的资源,虽然它会在最后由 GC 处理。