yanbolan
文章282
標籤199
類別26
gc非托管内存泄露

gc非托管内存泄露

实现 Dispose 方法 - .NET | Microsoft Learn

1
2
3
4
5
public void Dispose()
{
Dispose(disposing: true);//调用之后就不需要再调用后面
GC.SuppressFinalize(this);//请求公共语言运行时不要调用指定对象的终结器。
}

对于应用创建的大多数对象,可以依赖 .NET 垃圾回收器来进行内存管理。 但是,如果创建包含非托管资源的对象,则当你使用完非托管资源后,必须显式释放这些资源。 最常用的非托管资源类型是包装操作系统资源的对象,如文件、窗口、网络连接或数据库连接。 虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但无法了解如何发布并清理这些非托管资源。

如果你的类型使用非托管资源,则应执行以下操作:

  • 实现清理模式。 这要求你提供 IDisposable.Dispose 实现以启用非托管资源的确定性释放。 当不再需要此对象(或其使用的资源)时,类型使用者可调用 Dispose。 Dispose 方法立即释放非托管资源。

  • 在类型使用者忘记调用 Dispose 的情况下,请提供一种方法来释放非托管资源。 有两种方法可以实现此目的:

    • 使用安全句柄包装非托管资源。 这是推荐采用的方法。 安全句柄派生自 System.Runtime.InteropServices.SafeHandle 抽象类,并包含可靠的 Finalize 方法。 在使用安全句柄时,只需实现 IDisposable 接口并在 Dispose 实现中调用安全句柄的 IDisposable.Dispose 方法。 如果未调用安全句柄的 Dispose 方法,则垃圾回收器将自动调用安全句柄的终结器。

      —或—

    • 定义终结器。 当类型使用者无法调用 IDisposable.Dispose 以确定性地释放非托管资源时,终止会启用对非托管资源的非确定性释放。

       警告

      对象终止是一项复杂且易出错的操作,建议你使用安全句柄而不是提供你自己的终结器。

然后,类型使用者可直接调用 IDisposable.Dispose 实现以释放非托管资源使用的内存。 在正确实现 Dispose 方法时,安全句柄的 Finalize 方法或 Object.Finalize 方法的重写会在未调用 Dispose 方法的情况下阻止清理资源。


大概意思是说要显示调用dispose,dispose会通知 终结器线程 去处理:终结器线程会通过线程、进程交流 与对应的线程去释放;

参考com组件的STA单线程套间

终结器(以前称为析构器)用于在垃圾回收器收集类实例时执行任何必要的最终清理操作。 在大多数情况下,通过使用 System.Runtime.InteropServices.SafeHandle 或派生类包装任何非托管句柄,可以免去编写终结器的过程。

类似C++析构函数

在使用时,显示调用Dispose()方法,可以及时的释放资源,同时通过移除Finalize()方法的执行,提高了性能;如果没有显示调用Dispose()方法,垃圾回收器也可以通过析构函数来释放非托管资源,垃圾回收器本身就具有回收托管资源的功能,从而保证资源的正常释放,只不过由垃圾回收器回收会导致非托管资源的未及时释放的浪费

GC垃圾回收,GC.WaitForPendingFinalizers() - 禅道 - 博客园 (cnblogs.com)

由于垃圾回收是异步的,CLR有一个专用的线程负责垃圾回收,因此,即使调用GC.Collect,也并不是实时的调用了Finalize,因此要保证确实调用了析构方法,可以使用语句GC.WaitForPendingFinalizers()。

1
2
GC.Collect();//异步,
GC.WaitForPendingFinalizers();//确保释放

.NET 垃圾回收 | Microsoft Learn

Dispose由于必须显式调用 方法,因此始终存在不释放非托管资源的危险,


GDI

.NET 程序的 GDI 句柄泄露的再反思-51CTO.COM

GDIView工具不是很准


Using UMDH to Find a User-Mode Memory Leak - Windows drivers | Microsoft Learn

博主:yanbolan
文章連結:https://yuris.site/2023/09_10_43959cba.html
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×