C# 装箱、拆箱 底层原理

装箱 = 值类型 → 引用类型(堆上分配)

拆箱 = 引用类型 → 值类型(堆上取数据)

它们是隐式类型转换,底层由 CLR 自动完成。

1. 先搞懂两个基础:栈 和 堆

C# 内存分两块:

  • 栈(Stack) :存值类型(int、double、struct、bool),轻量、自动释放、速度极快。
  • 堆(Heap) :存引用类型(string、object、类实例),需要 GC 管理、速度慢。

值类型本身只在栈上,根本不在堆里。

2. 装箱(Boxing)底层到底做了什么?

cs 复制代码
int a = 10;        // 栈上的值类型
object obj = a;    // 这里发生了 **装箱**

底层 3 步动作(CLR 自动执行)

  • 在托管堆上分配一块新内存 大小 = 值类型本身大小 + 对象头(Type Handle + Sync Block)

  • 把栈上的值类型 复制 到堆上 栈上的 a = 10 原样拷贝到堆内存里。

  • 返回堆上对象的地址 赋值给 obj 引用变量。

内存变化图

cs 复制代码
【栈】             【堆】
a = 10        →    分配新对象
                 拷贝 10 进去
obj = 堆地址  ←   返回堆地址

一句话

装箱 = 堆上新建对象 + 栈数据拷贝到堆

3. 拆箱(Unboxing)底层做了什么?

cs 复制代码
object obj = 10;   // 先装箱
int b = (int)obj;  // 这里发生 **拆箱**

底层 3 步动作

  • CLR 检查堆上对象 确认它确实是被装箱的 int ,不是别的类型,否则直接抛 InvalidCastException。

  • 获取堆中值类型数据的地址 找到堆里那个真正的 10。

  • 把数据 复制回栈 拷贝到栈上的变量 b 里。

内存变化

cs 复制代码
【堆】          【栈】
装箱的 int  →  取出值 10
              复制到 b
b = 10

一句话

拆箱 = 类型检查 + 堆数据拷贝回栈

4. 性能代价(为什么要少用装箱?)

装箱的成本(非常高)

  1. 堆内存分配

  2. 数据拷贝

  3. GC 压力(堆对象多了,GC 就要干活)

拆箱的成本

  1. 类型检查

  2. 数据拷贝

对比

  • 直接赋值:1 个 CPU 指令

  • 装箱:几十~上百个 CPU 指令

频繁装箱 = 程序明显变慢。

5. 最容易触发装箱的 3 种代码

1)把值类型扔进 object / 非泛型集合

cs 复制代码
int a = 10;
object b = a;       // 装箱

ArrayList list = new ArrayList();
list.Add(10);       // 装箱!

2)值类型调用 ToString () / GetHashCode () 等重写方法

cs 复制代码
int a = 10;
string s = a.ToString(); // **不装箱**(因为重写了)

int a = 10;
a.GetType();         // 装箱!(没重写,会转成 object)

3)字符串拼接 + 值类型

cs 复制代码
int a = 10;
string s = "年龄:" + a;  // 装箱!

C# 会把 a 转成 object 再拼接。

6. 如何避免装箱?

  • 用泛型集合 (List<int> 而不是 ArrayList)
  • 避免值类型转 object
  • 字符串拼接用 $"" 或 string.Format 不会装箱(C# 编译器优化)
  • 用重载方法,不要传 object

装箱

  • 栈 → 堆

  • 分配堆内存

  • 拷贝值类型数据

  • 返回引用

  • 性能开销大

拆箱

  • 堆 → 栈

  • 类型检查

  • 拷贝数据回栈

  • 必须类型完全匹配

本质

装箱拆箱 = 内存拷贝 + 栈堆转换

总结

  • 装箱 :值类型 → 引用类型,堆分配 + 数据拷贝
  • 拆箱 :引用类型 → 值类型,类型检查 + 数据拷贝回栈
  • 成本:装箱 > 拆箱 > 普通赋值
  • 优化:用泛型、避免转 object、避免频繁字符串拼接
相关推荐
波力海苔夹心脆67510 小时前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
AI导出鸭PC端13 小时前
Perplexity批量导出没有PDF模式?AI导出鸭插件补上最后一块拼图
人工智能·pdf·c#·ai导出鸭
Risehuxyc14 小时前
C# 选用更流行的语言版本
c#
淡海水1 天前
09-04-内存-Unity原生对象生命周期
unity·c#·游戏引擎·gc
吴可可1232 天前
富怡CAD二次开发指南
c#
1-1=02 天前
C# IO和序列化
c#·.net·.netcore
寂寞的船2 天前
【Unity Bug挑战】第10期 SerializeReference 内存泄漏之谜
unity·c#·游戏引擎·bug
CSharp精选营2 天前
从控制台到「会动手」的 AI:用 Semantic Kernel 搭应用(小白教程)
c#·.net·ai agent·semantickernel·functioncalling
宝桥南山3 天前
.NET 11 - 尝试一下Blazor中的新特性SupplyParameterFromTempData
microsoft·微软·c#·asp.net·.net·.netcore
1-1=03 天前
C# 中 Lambda、Linq 与 Expression
c#·linq