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、避免频繁字符串拼接
相关推荐
步步为营DotNet18 小时前
探秘.NET 11:C# 14 特性在后端性能优化中的深度应用
性能优化·c#·.net
Chris _data19 小时前
C# 与 PLC Modbus RTU 通信实践:从单例到线程安全的连接监控
开发语言·安全·c#
Chris _data19 小时前
C# WinForms 后台轮询 Modbus 数据与 UI 更新实践
开发语言·ui·c#
魔法阵维护师19 小时前
从零开发游戏需要学习的c#模块,第二十四章(场景管理 —— 标题、游戏、结束画面)
学习·游戏·c#
唐青枫19 小时前
别把登录写散了:C#.NET IdentityServer4 统一认证与 JWT 授权实战
c#·.net
魔法阵维护师21 小时前
从零开发游戏需要学习的c#模块,第二十三章(存档与高分系统)
学习·游戏·c#
加号31 天前
【C#】 字符串字节到十六进制字节数组的转换解析
c#
JaydenAI1 天前
[MAF的Agent管道详解-04]如何让LLM按照要求的结构输出数据?
ai·c#·agent·maf·agent pipeline
不会编程的懒洋洋1 天前
VisionPro 中 几何相交工具 Geometry-Intersection
图像处理·笔记·c#·视觉检测·机器视觉·visionpro
不会编程的懒洋洋1 天前
VisionPro 中 图像预处理工具
图像处理·笔记·c#·视觉检测·visionpro