gc非托管内存泄露
title: gc非托管内存泄露
tags:
- net
cover: 'https://tuapi.eees.cc/api.php?category=dongman&type=302'
abbrlink: 43959cbadate: 2023-09-10 10:26:18
实现 Dispose 方法 - .NET | Microsoft Learn
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()。
GC.Collect();//异步,
GC.WaitForPendingFinalizers();//确保释放
Dispose由于必须显式调用 方法,因此始终存在不释放非托管资源的危险,
GDI
.NET 程序的 GDI 句柄泄露的再反思-51CTO.COM
GDIView工具不是很准
Using UMDH to Find a User-Mode Memory Leak - Windows drivers | Microsoft Learn