声明一个值类型变量,编译器会在栈上分配一个空间,这个空间对应着该值类型变量,空间里存储的就是该变量的值。指针
引用类型的实力分配在堆上,新建一个引用类型实例,获得的变量对应的是该实例的内存分配地址,这就像您的银行帐号同样。code
1: public static class BoxingAndUnboxing 2: { 3: public static void Demonstration() 4: { 5: int ageInt = new int(); 6: 7: // Boxing operation. 8: object ageObject = ageInt; 9: 10: //ageObject = null; 11: 12: // Unboxing operation. 13: ageInt = (int)ageObject; 14: 15: Console.WriteLine(ageInt); 16: } 17: }
在该方法中,咱们首先声明了一个值类型变量ageint,但并未给它赋值,接着声明了一个典型的引用类型变量ageobject,并把ageint赋给它,这里就进行了一次装箱操做。编译器如今托管堆上分配一块内存空间(空间大小为对象中包含的值类型变量所占空间总和外加一个方法表指针和一个syncblockindex),而后把ageint拷贝到这个空间中,再返回该空间的引用地址,接下来第13行是拆箱操做,编译器获取到ageobject对象中值类型变量的指针,而后将其值拷贝给值类型变量。若是你把第10行的代码打开,程序不会报错,最后打印出个0,这说明在声明值类型变量时,若是没有初始化赋值,编译器会自动将其赋值为0,既然值类型没有引用,那么它就不可能为空。引用类型不同,它能够为空引用,一张过时做废的银行卡能够存在。而若是将一个空的对象装箱,编译器上哪儿区找它里面的值类型变量的指针呢?因此这也是拆箱操做须要注意的地方。对象
未装箱的值类型分配在栈上而不是堆上,而栈又不是GC的地盘儿,所以GC根本不过问值类型变量的死活,一旦值类型变量的做用范围一过,它所占的空间就当即被回收掉,不劳GC亲自动手。内存