托管/非托管资源
托管资源:通常指由 CLR(公共语言运行时)管理生命周期的资源,主要就是托管堆上的对象内存。这些资源不需要你自己直接释放,垃圾回收器(GC)会在合适的时候回收。
非托管:指不受 CLR 直接管理的资源。GC 只能管 .NET 对象内存,管不了操作系统句柄、数据库连接、文件句柄、网络套接字、GDI 对象、非托管内存等。
托管资源
常见例子:
- string
- List
- 自定义类对象
- 普通数组
- 大多数纯 .NET 对象
例如:
1 | var list = new List<int>(); |
这里的数组就是托管资源,由GC回收。
非托管资源
常见例子:
- 文件句柄
- 数据库连接
- Socket 连接
- 窗口句柄
- 非托管内存(如 Marshal.AllocHGlobal 分配的内存)
- 调用 C/C++ DLL 获得的资源
例如:
1 | var fs = new FileStream("a.txt", FileMode.Open); |
FileStream 对象本身是托管对象,但它内部持有的文件句柄是非托管资源。
易混点
“对象”本身和“对象持有的资源”不可混为一谈。
例如:
1 | var conn = new SqlConnection(connectionString); |
- conn 这个对象:托管对象
- 它内部占用的数据库连接等底层资源:非托管资源
所以常说:一个托管对象,可能封装着非托管资源。
因为 GC 不知道这些非托管的底层资源什么时候该释放。
如果只等 GC 回收对象,可能会导致:
- 文件一直被占用
- 数据库连接不及时归还
- 内存泄漏
- 句柄耗尽
通常需要通过 IDisposable 和 using 显式释放,避免资源泄漏。