谈CLR的装箱与拆箱
2010-12-29 11:53 姜 萌@cnblogs 阅读(2383) 评论(11) 编辑 收藏 举报CLR类型系统有两种主要类型—Reference Type和ValueType。前者是在托管堆中被分配内存并接受管理,后者则有两种形态--装箱与未装箱,对于装箱形态的值对象是在托管堆中,未装箱形态的值对象是在栈上分配。
CLR堆上对象和栈上对象的差异
每一个堆上对象都有两个额外的字段,一个是类型引用表的指针,用于实现多态,类似于C++的多态机制,另一个字段是SyncBlockIndex,用于实现CLR线程同步机制。栈上对象则无这两个字段。
装箱的过程
装箱:
在堆上开辟内存,包括2个额外字段+值对象大小。
将值对象复制过去
3.返回新分配对象的地址。
拆箱的过程
1.如果为null,跑出NullReferenceException
2.如果引用指向的不是一个期望对象的已装箱对象,跑出InvalidCastException。
3.得到堆上引用对象中未装箱对象的指针。
两者是反过程吗
对比上述装箱和拆箱的过程,可以看出两者并非是互为反操作,拆箱过程本身并不涉及内存操作,不会像装箱那样拷贝数据,但是拆箱之后通常也还是要将值从堆上进行拷贝的栈上的。
性能差异
了解了装箱和拆箱的操作,我们可以清楚的明白:装箱操作会导致数据在堆和栈上进行拷贝,频繁的装箱操作会性能损失。而相比而言拆箱过程对性能损耗还是比较小的。
发现代码中的装箱和拆箱操作
1)
Int32 a = 100;
object b = a;//(A)
a = (int)b;//(B)
(A)发生一次装箱操作
(B)发生一次拆箱操作。
2)
Point p = new Point(1,5);
Console.WriteLine(p.Clone());//(A)
var p2 = p as ICloneable;//(B)
var p3 = (Point)p2;//(C)
(A):Point重载了Clone()方法,所以这一步无需借助多态,p本身不会被装箱。但是要注意:Clone返回的是一个object,所以这一步会出现一个装箱操作。
(B):会产生装箱操作
(C):这一步会出现拆箱操作,并发生内存拷贝(从托管堆上拷贝到栈上)。
使用ILDASM查看IL代码
vs自带的tools里提供了一个ILDASM的工具,能够查看程序集的IL代码。
在vs的命令行环境下(command prompt)执行“ILDASM /adv”,/adv参数能开启一些高级操作。打开一个未混效过的程序集,我们就能查看到其IL代码,相信您能从中发现更多有趣的东西:)