C#Dispose模式 转载 https://www.cnblogs.com/xyzf/p/9021513.html
- 目的:
为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率
- 必须遵循的事实:
1 托管资源释放:
由另一线程的gc进行释放,当托管的对象没有被引用时,就会在“适当的时候”进行回收
如果定义了析构函数,回收的时候会调用析构函数(实际执行可能有差别),之后释放对象占用的内存。
当类有析构函数时, gc会分分两步来释放,如果没有析构函数或者指定不需要调用析构函数时,只需要一步就能释放
2 非托管资源必须显式释放
- 方案:
1.把资源释放都放在析构函数里。
可以保证资源都释放,但是由于gc调用时机的不确定性,导致宝贵的非托管资源无法及时释放。
2. 写个释放函数,手动是调用
如果忘了释放的话, 托管资源会被gc释放,但非托管资源就无法释放
3. Dispose模式。参考下面的代码
手动调用Dispose() 可以释放所有资源,并且在gc标记不需要再调用析构函数,从而提高了效率。
如果忘记调用Dispose(), 则当gc调用析构函数的时候也会把非托管资源释放掉
-------参考代码-----------
public interface IDisposable { void Dispose(); } public class DisposablClass : IDisposable { //是否回收完毕 bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); //标记gc不在调用析构函数 } ~DisposableClass() { Dispose(false); } private void Dispose(bool disposing) { if(_disposed) return; //如果已经被回收,就中断执行 if(disposing) { //TODO:释放本对象中管理的托管资源 } //TODO:释放非托管资源 _disposed = true; } }
- 可能存在的疑问
1. 既然gc是另外一线程执行的,为什么Dispose(bool)函数里不加锁?
答:因为如果可以主动调用的时候,肯定此对象不是死对象,也不会被回收,因此不会同时调用到
2. 为什么析构函数调用的dispose(false)不释放托管资源?
答:因为析构函数由gc来调用,gc会依次释放所有的死对象(不可到达),释放的顺序是随机的,如果在一个对象的析构里调用了一个本次gc已经释放的对象,就会发生释放两次的错误。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律