从类创建角度看托管资源还是非托管资源

时间:2018-10-24 17:13:01

标签: c# garbage-collection

我想了解的是创建自己的类时,我如何知道什么是托管资源还是非托管资源,因此我知道我的类是否需要提供清理它的能力,或者GC是否最终会做它。另外,更深入一点,当我创建一个.Dispose()方法时,将有一个托管资源块和一个非托管资源块,以及我如何知道应该在哪个块中清理哪些资源。

我已经阅读了C#程序中有关托管资源与非托管资源的许多答案,但是大多数答案都提供了有关GC清理的定义,因为“托管资源由GC清理而非托管资源则不是”。这对我没有帮助,因为我看不到GC如何确定将要清除的内容以及将留下的内容。我也了解,如果类提供了.Dispose()方法,则我的程序应执行该方法。

我已经看到答案,说明如果使用WIN32 API,则创建了非托管资源。如果我不调用WIN32 API,是否意味着我没有任何非托管资源?我也偶然发现了马歇尔。马歇尔还会创建非托管资源吗?还有其他“关键字/类”可用于标识我正在创建非托管资源吗?

请从答案中排除所有有关“占用大量内存的托管资源”的信息。我知道可以释放此内存是很好的选择,但这不是必需的,因为GC最终会做到这一点,只是不一定总是及时。

1 个答案:

答案 0 :(得分:0)

通常,如果您没有跨越本机代码和托管代码的界限,则不必费心释放类中的非托管资源。

在运行.NET应用程序时,框架会为其在内存中分配一个托管片,几乎可以从.NET框架访问的所有内容都将由GC存储和跟踪。其他所有内容都落在此片段之外,而GC则没有敏锐的眼睛。

因此,对于您有关GC如何确定应收集哪些资源以及不收集哪些资源的问题,简短的答案是,它对非托管资源一无所知,因此也无法收集它们。

这些世界-本机和托管世界是分开的,但它们可以彼此通信,这就是 Marshalling 的目的。您可以详细了解here。有了它,您当然可以创建非托管资源,但这并不意味着您每次使用它时都会做。

还有些极端的说法是,每次使用Win32 API时,都会创建必须释放的本机资源。 当您在任何创建指针的本机代码上使用 Platform Invoke C ++ / CLI包装器调用时,或应在本机世界中手动释放的任何内容(当然,这些不是由GC跟踪),如果本机端尚未发布它们,则必须手动释放它们。但是,如果您使用仅适用于原始类型的API,则不必释放任何内容。

如果您没有从上方使用任何内容,则很有可能不必为直接释放不受管理的任何内容准备类。

有些类型使用本机资源-您可能已经遇到过-这些是在后台管理的包装器。他们通过编组在onButtonGroupClick实现中释放这些资源。

例如,Dispose托管类持有给定文件的非托管句柄。 FileStream本身是GC跟踪和收集的托管类,但非托管句柄不是,必须手动释放它,因此,FileStream的用户如果不调用它的{{ 1}}方法中,该句柄将保留在内存泄漏中,直到应用程序退出。