装箱拆箱

装箱和拆箱

什么是装箱和拆箱。它其实很简单,把值类型实例转换为引用类型实例,就是装箱。相反,把引用类型实例转换为值类型实例,就是拆箱。

// 装箱
int a = 5;
object obj = a;

//拆箱
a = (int)obj;

值类型数据会直接存储变量
装箱,因为a 是值类型是直接有数据的变量,obj为引用类型是指针与内存是拆分开来的,把 a 赋值给 b 实际上就是 b 为自己创建了一个指针并指向了a的数据空间。

引用类型的变量会在声明时预留出内存地址,其为null, 当进行new创建实例的时候,就分配了堆上的内存空间,把空间地址保存给这个引用变量。

拆箱,相当于把 obj 指向的内存空间复制一份交给了a,因为 a 是值类型,它不允许指向某个内存空间只能靠复制数据来传递数据。

为何需要装箱

栈是本着先进后出的数据结构(LIFO)原则的存储机制,它是一段连续的内存,所以对栈数据的定位比较快速, 而堆则是随机分配的空间,
处理的数据比较多, 无论如何,
至少要两次定位。堆内存的创建和删除节点的时间复杂度是O(logn)。栈创建和删除的时间复杂度则是O(1),栈速度更快。

那么既然栈速度这么快,全部用栈不就好了。这又涉及到生命周期问题,由于栈中的生命周期是必须确定的,销毁时必须按次序销毁,从最后分配的块部分开始销毁,创建后什么时候销毁必须是一个定量,所以在分配和销毁时不灵活,基本都用于函数调用和递归调用中,这些生命周期比较确定的地方。相反堆内存可以存放生命周期不确定的内存块,满足当需要删除时再删除的需求,所以堆内存相对于全局类型的内存块更适合,分配和销毁更灵活。

当程序、逻辑或接口需要更加通用的时候才会需要装箱。比如调用一个含类型为object的参数的方法,该object可支持任意为型,以便通用。当你需要将一个值类型(如Int32)传入时,就需要装箱。又比如一个非泛型的容器为了保证通用,而将元素类型定义为object,当值类型数据加入容器时需要装箱。

装箱的内部操作

装箱: 根据相应的值类型在堆中分配一个值类型内存块,再将数据拷贝给它。按三步进行。

  • 第一步:在堆内存中新分配一个内存块(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)。
  • 第二步:将值类型的实例字段拷贝到新分配的内存块中。
  • 第三步:返回内存堆中新分配对象的地址。这个地址就是一个指向对象的引用了。

拆箱 :更为简单点,先检查对象实例,确保它是给定值类型的一个装箱值,再将该值从实例复制到值类型变量的内存块中。

装箱、拆箱对执行效率有哪些影响,如何优化。

由于装箱、拆箱时生成的是全新的对象,不断得分配和销毁内存会不但大量消耗CPU,也同时增加了内存碎片,降低了性能。 那该如何做呢?

最需要我们做的就是减少装箱、拆箱的操作,在我们编程规范中要牢记这种比较浪费CPU的操作,在平时编程要特别注意。

整数、浮点数、布尔等数值型变量的变化手段很少,变不出什么花样来,主要靠加强规范减少装拆箱的情况来提高性能。Struct 有点不一样,它既是值类型,又可以像类一样继承,用途多转换的途径多可变的花样多,稍不留神花样就变成了麻烦,所以这里讲讲 Struct 变化后的优化方法。

  1. Struct 通过重载函数来避免拆箱、装箱。 ToString(), GetType(), 如果 Struct 没有写重载ToString()和GetType()的方法,就会在 Struct 实例调用它们时先装箱再调用,导致内存块重新分配性能损耗,所以对于那些需要调用的引用方法,必须重载。
  2. 通过泛型来避免拆箱、装箱。 不要忘了 Struct 也是可以继承的,在不同的、相似的、父子关系的 Struct 之间可以用泛型来传递参数,这样就不用装箱后再传递了。
    比如B,C继承A,就可以有这个泛型方法 void Test(T t) where T:A,以避免使用object引用类型形式传递参数。
  3. 通过继承统一的接口提前拆箱、装箱,避免多次重复拆箱、装箱。 很多时候拆装箱不可避免,那么我们就让多种 Struct 继承某个统一的接口,不同的 Struct 就可以有相同的接口。把 Struct 传递到其他方法里去时就相当于提前进行了装箱操作,在方法中得到的是引用类型的值,并且有它需要的接口,避免了在方法中重复多次的拆装箱操作。比如 Struct A 和 Struct B 都继承接口 I,我们调用的方法是 void Test(I i)。当调用Test方法时传进去的 Struct A 或 Struct B 的实例都相当于提前做了装箱操作,Test里拿到的参数后就不用再担心内部再次装箱拆箱问题了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值