简单的说
装箱:值类型转成引用类型
拆箱:引用类型转成值类型
这里就执行了装箱和拆箱操作。
Box和Unbox的解释参考官网:
说说装箱的步骤:
0、将值入栈,(注意,不管这个值是在堆,还是在栈,还是在哪里,都需要先将值入栈)
1、在托管堆中分配内存。分配的内存量是值类型各字段所需的内存量,还要加上类型对象指针和同步块索引所需的内存量
2、把入栈的值,弹出栈,复制到新分配的堆里
3、返回对象地址,把地址入栈
注:两个开销字段——类型对象指针和同步块索引,所需的内存在32位应用程序上需要4+4=8个字节,64位上是16字节
看看例子:object obj = 3;装箱步骤
0、它是先将值3入栈
1、在托管堆中分配内存,在32位应用上是 4(int所需的内存) + 8 = 12个字节
2、把3弹出栈,并复制到新分配的内存堆里
3、把新地址入栈
在申请堆空间的时候,有可能会触发GC。
注意,obj那个3和入栈那个3不是一个东西了。看如下代码的输出:
修改了i,但是obj的值依然是3.
下面看个例子:
int i = 3; object obj = i; Console.WriteLine(i + ", obj: " + (int)obj);
这个代码会进行三次装箱,因为字符串的+用的是String::Concat(object, object, object);
int i = 3; object obj = i; Console.WriteLine(i.ToString() + ", obj: " + obj);
这个代码只会进行一次装箱,即obj = i需要装箱,而i.ToString和obj传给Concat都不会装箱处理。
Obj不进行装箱,因为它本来就是引用类型,这个比较好理解
但i.ToString()这个,涉及的就有点麻烦,参考下图:
此图是《CLR via C#》 (第4版) 周靖 译 的第118页
注意:引用类型下的所有内存都是从托管堆(堆)分配,使用引用类型要注意性能问题。
这里留两个坑:
1、C#的堆和栈到底有啥区别?
2、CLR的GC机制是啥?
来源:https://www.cnblogs.com/woniu89/p/12364004.html