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、避免频繁字符串拼接
相关推荐
清风明月一壶酒2 小时前
OpenClaw自动处理Word文档全流程
开发语言·c#·word
工程师0075 小时前
C# 值类型 / 引用类型 内存布局(栈、堆、托管堆)
c#·值类型与引用类型
chao1898448 小时前
完整MES系统实现 (C# 客户端服务器)
服务器·windows·c#
月昤昽8 小时前
autocad二次开发 2.旋转
c#·autocad·autocad二次开发
rockey6278 小时前
基于AScript的python3脚本语言发布啦!
python·c#·.net·script·python3·eval·expression·function·动态脚本
工程师0078 小时前
C# 字符串不可变性 + 字符串驻留池原理
c#·字符串拘留池
唐青枫14 小时前
内存为什么越来越高?C#.NET GC 详解:分代回收、LOH、终结器与性能优化实战
c#·.net
xiaohe0715 小时前
C#数据库操作系列---SqlSugar完结篇
网络·数据库·c#
yngsqq1 天前
平面图环 内轮廓
c#