C#内存管理由CLR自动处理,核心是垃圾回收器(GC);值类型通常栈上分配、按值传递,引用类型堆上分配、按引用传递;需避免装箱/拆箱、大对象频繁分配,并用IDisposable及时释放非托管资源。

C#内存管理的核心机制
C#的内存管理主要由.NET运行时(CLR)自动处理,开发者无需手动分配或释放内存。核心是垃圾回收器(GC)——它定期扫描堆内存,识别并回收不再被引用的对象。但“自动”不等于“无感”:理解栈与堆的分工、值类型与引用类型的存储差异,才能写出高效、低内存泄漏风险的代码。
值类型:通常在栈上分配,轻量且独立
值类型直接存储数据本身,常见于int、bool、char、struct、enum等。它们默认在栈上分配(局部变量时),生命周期由作用域决定——方法执行完,栈空间自动释放,不触发GC。
- 赋值时是逐字节复制,两个变量完全独立,修改一个不影响另一个
- 可为null?默认不能,但可通过int?(即Nullable
)支持空值 - 结构体(struct)虽是值类型,但如果内部包含引用类型字段(如string),该字段本身仍存在堆上
引用类型:对象在堆上,变量存的是地址
引用类型包括class、string、array、delegate、interface等。变量本身(4字节或8字节)存在栈上(或寄存器中),而真正的对象实例分配在托管堆(Managed Heap)上。
- 赋值只是复制引用(地址),多个变量可能指向同一块堆内存
- 当所有引用都消失(不可达),GC会在下次回收周期将其标记为可回收
- string虽是引用类型,但具有“不可变性”和“字符串驻留(interning)”特性,相同字面量常共享同一堆内存地址
容易忽略的关键细节
不是所有值类型都一定在栈上:当值类型作为类的字段、装箱(boxing)、或被闭包捕获时,会被提升到堆上;同样,引用类型的变量也可能因逃逸分析被优化到栈上(.NET Core 2.1+ JIT优化)。所以更准确的说法是:值类型按值语义操作,引用类型按引用语义操作,而物理位置由JIT和运行时综合决策。
- 避免频繁装箱/拆箱(如把int传给object参数),会额外分配堆内存并触发GC
- 大对象(≥85KB)直接进入大对象堆(LOH),GC回收开销更大,尽量复用或使用Span
/Memory 替代 - 实现IDisposable接口用于及时释放非托管资源(如文件句柄、数据库连接),配合using语句确保调用Dispose()










