内存布局
值类型:存储在栈上,当变量超出作用域时自动释放。
引用类型:存储在堆上,由垃圾回收器管理其生命周期。包括对象头部信息和实际数据。
装箱过程
分配内存:在托管堆上分配内存,用于存储值类型的数据以及对象头部信息。
复制数据:将栈上的值类型数据复制到新分配的堆内存块中。
创建引用:返回一个指向该堆内存块的引用,即object类型的变量。
拆箱过程
类型检查:确认object引用实际包含的类型与目标值类型一致。如果不一致,会抛出InvalidCastException异常。
获取地址:从object引用中提取原始值类型的地址。
复制数据:将堆中的值类型数据复制回栈上的变量。
代码事例
using System;
class Program
{
static void Main()
{
// 值类型变量
int value = 42;
// 装箱过程
object boxedValue = value; // 在堆上分配内存,并复制数据
// 内存布局:
// 栈:value (42)
// 堆:boxedValue (Object Header + 42)
// 拆箱过程
try
{
int unboxedValue = (int)boxedValue; // 从堆中提取值并复制到栈上
Console.WriteLine("成功拆箱后的值: " + unboxedValue); // 输出:42
}
catch (InvalidCastException e)
{
Console.WriteLine("拆箱失败:" + e.Message);
}
// 错误的拆箱(类型不匹配)
try
{
double wrongUnbox = (double)boxedValue; // 会引发 InvalidCastException
}
catch (InvalidCastException e)
{
Console.WriteLine("错误的拆箱:" + e.Message); // 输出:Specified cast is not valid.
}
}
}
内存模型简图
装箱过程
1 值类型在栈上:
+-----+
| 42 |
+-----+
2 装箱后,在堆上:
栈:
+-------------+
| boxedValue | --------> +------------------+
+-------------+ | Object Header |
+------------------+
| 42 |
+------------------+
拆箱过程
1 拆箱前:
栈:
+-------------+
| boxedValue | --------> +------------------+
+-------------+ | Object Header |
+------------------+
| 42 |
+------------------+
2 拆箱后:
栈:
+-------------+ +------------------+
| boxedValue | --------> | Object Header |
+-------------+ +------------------+
| 42 | <-------- | 42 |
+-------------+ +------------------+
通过理解装箱和拆箱的内存过程,你可以更好地优化代码性能,并避免不必要的装箱和拆箱操作,从而减少性能开销