CLR、托管、非托管 之一
** CLR 与托管/非托管的关系**
-
CLR(Common Language Runtime) 是 .NET 的运行时环境:
-
托管代码运行在 CLR 上,由它提供:
- 内存管理(GC)
- 类型安全
- 异常处理
- 安全控制
-
非托管代码 不运行在 CLR 上,所以 CLR 不直接管理它,需要通过互操作(Interop)桥接:
- P/Invoke(Platform Invoke) 调用 DLL
- COM Interop 调用 COM 对象
-
-
换句话说:
- 托管代码/资源 → CLR 管理
- 非托管代码/资源 → CLR 不管理,需要手动处理
- CLR 只是管理托管世界的“保护者”,非托管世界 CLR 不干涉。
1️⃣ 托管 vs 非托管 —— 基础概念
(1)托管资源 / 托管代码
-
托管代码(Managed Code):
由 **.NET CLR(Common Language Runtime,通用语言运行时)** 执行和管理的代码。
- 特点:CLR 提供内存管理(垃圾回收)、类型安全、异常处理、安全性等机制。
- 示例:C#、VB.NET 写的代码在 .NET 下编译成 IL(中间语言),运行在 CLR 上就是托管代码。
-
托管资源(Managed Resource):
-
由 CLR 自动管理其生命周期的资源。
-
典型例子:
- 托管对象(C# 中的
class
实例,存放在堆上,由 GC 回收) - 托管内存(CLR 分配的堆内存)
- 托管文件句柄、数据库连接(通过托管类封装)
- 托管对象(C# 中的
-
特点:开发者不需要手动释放,CLR 会自动回收。
-
(2)非托管代码 / 非托管资源
-
非托管代码(Unmanaged Code):
-
不受 CLR 直接管理的代码。
-
一般是 操作系统原生代码 或 传统编译语言生成的二进制:
- C、C++、汇编生成的 DLL 或 EXE。
-
特点:
- 内存和资源管理由程序员自己控制(malloc/free、new/delete)。
- 不具备 CLR 的类型安全、垃圾回收等保护机制。
-
-
非托管资源(Unmanaged Resource):
-
CLR 或 .NET GC 无法自动管理的资源,需要程序员手动释放。
-
典型例子:
- 文件句柄(FileHandle)
- 数据库连接(直接用 Win32 API)
- 窗口句柄、套接字、GDI+ 对象、非托管内存
-
使用注意:
- 必须在不需要时及时释放(例如实现
IDisposable.Dispose()
,或者使用using
块)。
- 必须在不需要时及时释放(例如实现
-
2️⃣ 划分标准
分类 | 判断标准 | 典型示例 | 谁管理 |
---|---|---|---|
托管代码 | 由 CLR 执行 | C# IL、VB.NET IL | CLR(垃圾回收) |
非托管代码 | 不受 CLR 管理 | C/C++ DLL | 程序员/操作系统 |
托管资源 | 在托管堆或 CLR 控制下的资源 | C# 对象实例、托管内存 | CLR GC |
非托管资源 | CLR 无法控制的资源 | 文件句柄、数据库连接、非托管内存 | 程序员 |
3️⃣ 核心区别
区别点 | 托管 | 非托管 |
---|---|---|
内存管理 | CLR 自动回收 | 程序员手动管理 |
安全性 | 类型安全、有异常处理、沙箱保护 | 无类型安全,容易出错 |
生命周期 | CLR GC 控制 | 开发者控制(容易泄漏) |
调用方式 | 直接调用 | P/Invoke 或 COM Interop |
适用语言 | C#, VB.NET 等 | C, C++, Delphi 等 |
4️⃣ 使用注意事项
托管资源/代码
- 不用手动释放内存(GC 会回收)。
- 尽量避免非必要的对象创建,减少 GC 压力。
- 对外部资源(文件、数据库、网络)仍然需要使用
IDisposable
或using
来确保及时释放。
非托管资源/代码
-
必须手动管理生命周期,避免资源泄漏。
-
在托管代码中使用非托管资源,需要通过:
IDisposable
+using
模式SafeHandle
/CriticalHandle
来安全封装非托管资源- P/Invoke 调用非托管函数时注意内存分配和释放
-
需要注意异常安全,确保资源在异常时也能释放。
✅ 总结逻辑图(文字版):
[托管代码] --运行在--> CLR --管理--> [托管资源]
[非托管代码] --不受--> CLR 管理 --> [非托管资源]
托管代码 可通过 P/Invoke 调用 非托管代码/资源