c# - 从类创建的角度来看,托管资源与非托管资源
问题描述
我想了解的是,当我创建自己的类时,我怎么知道什么是托管资源和非托管资源,所以我知道我的类是否需要提供清理它的能力,或者 GC 是否最终会这样做。此外,更深入一点,当我创建一个 .Dispose() 方法时,将有一个用于托管资源的块和一个用于非托管资源的块,以及我如何知道哪些资源应该在哪个块中清理。
我已经阅读了许多关于 C# 程序中托管资源与非托管资源的答案,但其中大多数都提供了关于 GC 清理的定义,如“托管资源由 GC 清理而非托管资源不是”。这对我没有帮助,因为我看不到 GC 如何确定它将清理什么以及它将留下什么。我也明白,如果一个类提供了一个 .Dispose() 方法,我的程序应该执行它。
我看到的答案表明,如果我使用 WIN32 API,我就创建了一个非托管资源。如果我不调用 WIN32 API,这是否意味着我没有任何非托管资源?我也偶然发现了马歇尔。Marshall 是否也创建非托管资源?是否有其他“关键字/类”可用于识别我正在创建非托管资源?
请从您的答案中排除有关“占用大量内存的托管资源”的任何内容。我知道提供释放此内存的能力会很好,但这不是必需的,因为 GC 最终会这样做,只是并不总是及时。
解决方案
通常,如果您没有跨越本机代码和托管代码的界限,则不必费心在类中释放非托管资源。
当您运行 .NET 应用程序时,框架会在内存中为其分配一个托管切片,您可以从 .NET 框架访问的几乎所有内容都将被 GC 存储和跟踪。其他一切都在这个切片之外,没有 GC 的敏锐眼睛。
因此,对于您关于 GC 如何确定应该收集哪些资源以及不应该收集哪些资源的问题,简短的回答是它对非托管资源一无所知,因此它也无法收集它们。
这些世界——原生世界和被管理世界——是分开的,但它们可以相互交流,这就是编组的目的。你可以在这里阅读更多关于它的信息。当然,您可以创建非托管资源,但这并不意味着您每次使用它时都会这样做。
说每次使用 Win32 API 时都会创建必须释放的本机资源,这也有点极端。当您在任何本机代码上使用Platform Invoke或C++/CLI 包装器调用创建指针或任何应在本机世界中手动释放的内容时(这些当然不会被 GC 跟踪),您必须手动释放它们,如果它们尚未由本机方发布。但是,如果您使用仅适用于原始类型的 API,那么您无需发布任何内容。
如果你没有使用上面的任何东西,那么你很有可能不必为直接释放任何非托管的东西而准备你的类。
有些类型使用本机资源——你可能已经遇到过——它们是底层的托管包装器。他们Dispose
通过编组在实现中释放这些资源。
例如,FileStream
托管类持有给定文件的非托管句柄。它FileStream
本身是由 GC 跟踪和收集的托管类,但非托管句柄不是,它必须手动释放,因此如果您,用户FileStream
没有在代码中调用其Dispose
方法,则该句柄将保留在内存中泄漏,直到应用程序退出。
推荐阅读
- python - 只能使用{}而不是传入python?
- jena - 如何将 Jena 结果集加载到 Jena 模型
- css - 我正在尝试为 href="" 和使用 css的内容自动使用(几乎)相同的文本
- laravel - 用于更新的 Livewire 通行证 ID
- r - 插值以获得 R 中的某个值
- python-3.x - Django Queryset 而不是 view.py 中的 for 循环和 if 语句
- php - 在文件顶部添加带有 php simplexml 的新子节点
- python-3.x - 如何让 Tensorflow 使用更多的 RAM?
- c++ - 监视剪贴板更改 c++ 适用于所有应用程序 (Windows)
- c - 在不使用 strstr 的情况下从文件中提取包含字符串的行到另一个文件中