装箱拆箱

    科技2022-07-10  86

    装箱拆箱

    什么是装箱拆箱装箱拆箱 值类型与引用类型值类型引用类型 泛型性能消耗

    什么是装箱拆箱

    装箱 就是把“值类型”转换成“引用类型”; 拆箱 就是把“引用类型”转换成“值类型”;

    装箱

    把“值类型”转换成“引用类型”

    int i = 10; //值类型 object o = i; //引用类型

    具体过程:

    在堆中申请内存,内存大小为值类型的大小,再加上额外固定空间(类型对象指针和同步块索引)。将值类型的字段值拷贝到新分配的内存中。返回新引用对象的内存地址(给栈上的引用)。

    我们可以从图中看到,装箱就是生成图中除了一开始 i=1 的变量之外另外两块变量的过程。

    拆箱

    把“引用类型”转换成“值类型”

    int j = (int)o;

    拆箱不是直接将装箱过程倒过来,拆箱的代价比装箱要低的多,拆箱其实就是获取一个指针的过程。一个已装箱的实例在拆箱时,编译器在内部都干了下面这些事:

    如果包含了“对已装箱类型的实例引用”的变量为null时,会抛出一个NullReferenceException异常。如果引用指向的对象不是所期待的值类型的一个已装箱实例,会抛出一个InvalidCastException异常与拆箱比较,装箱的性能消耗更大,因为引用对象的分配更加复杂,成本也更高,值类型分配在栈上,分配和释放的效率都很高。装箱过程需要创建一个新的引用类型对象实例。

    值类型与引用类型

    值类型

    bool,byte,char,decimal,double,enum,float,int,long,sbyte,short,struct,uint,ulong,ushort统称为值类型值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。值类型变量声明后,不管是否已经赋值,编译器为其分配内存。

    引用类型

    class,delegate,interface,object,string统称为引用类型引用类型的对象总是在进程堆中分配(动态分配)。引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。

    泛型

    使用泛型可以减少装箱拆箱操作

    ArrayList list = new ArrayList(); //Add方法使用的object类型参数 //List<int> list = new List<int>(); //Add方法使用的int类型参数 list.Add(1);

    性能消耗

    装箱拆箱操作会对应用程序的速度和内存消耗产生不利的影响(例如消耗内存,增加垃圾回收次数,复制操作)通过深入了解装箱与拆箱的过程,我们可以知道其中包含了对堆上内存的操作,故会消耗性能,这是完全不必要的。另外值得注意的是,装箱需要比原数据更多的空间,因为它需要两个引用类型的标准配置:类型对象指针和同步块索引。
    Processed: 0.023, SQL: 8