[转]C#基元类型、引用类型和值类型以及装箱拆箱

基元类型(primitive type)
----------------------------------

编译器直接支持的类型。

sbyte / byte / short / ushort / int / uint / long / ulong

char / float / double / bool / decimal /object / string


值类型(value type)
------------------------------
值类型实例分配在堆栈(stack)上,值类型变量本身即包含实例所有字段,值类型不受垃圾回收器控制,在离开作用域后自动释放所占内存。所有值类型都继承自ValueType。值类型缺省状态下(未装箱)按值复制方式传递。

sbyte / byte / short / ushort / int / uint / long / ulong / char / float / double / bool / decimal / 枚举(enum) / 结构(struct)


引用类型(reference type)
------------------------------------
引用类型都全部或间接继承自Object,引用对象内存必须在托管堆(heap)中分配,引用类型变量包含对象在托管堆中的内存地址。每个引用类型对象实例都包含一些额外附加成员,且需要垃圾回收器回收才能释放内存。注意,引用本身在堆栈中分配。引用类型对象传递时只是复制引用(内存地址)。

引用对象(Object) / 数组(String) / 数组(Array) / 装箱后的值类型

  

引用类型和值类型区别

------------

  结构体直接继承自System.ValueType;而枚举直接继承自System.Enum, Enum类又直接继承自System.ValueType。

  下面通过例子看一下他们的区别:

  首先定义类和结构体:  

 class SomeRef { public Int32 x; } 
 struct SomeVal { public Int32 x; } 
 1 SomeRef r1 = new SomeRef(); // 分配到堆 
 2 SomeVal v1 = new SomeVal(); // 分配到栈 
 3 r1.x =5; // 所引用的堆空间内数据修改 
 4 v1.x =5; // 直接在栈上复赋值 
 5 Console.WriteLine(r1.x); // "5" 
 6 Console.WriteLine(v1.x); // "5" 
 7 SomeRef r2 = r1; //只把指针复制给了r2 
 8 SomeVal v2 = v1; // 在栈上分配空间,并且将变量内容进行复制 
 9 r1.x = 8; // r1指向(也是r2指向)的内容修改 
10 v1.x = 9; // 只修改v1内容,v2内容不会受影响 
11 Console.WriteLine(r1.x); // "8" 
12 Console.WriteLine(r2.x); // "8" 
13 Console.WriteLine(v1.x); // "9" 
14 Console.WriteLine(v2.x); // "5" 

  看看下图的内存分配情况,就一目了然了。

 

装箱
-------------

装箱:将值类型转换为引用类型。当我们把值类型参数传递给需要引用类型参数的方法时,会自动进行装箱操作。

步骤:
1. 从托管堆分配内存,包括添加方法表指针和SyncBlockIndex。
2. 将值类型字段拷贝到该内存。
3. 返回该地址的引用。


拆箱
------------

拆箱:获取指向对象中包含的值类型部分的指针。一般拆箱之后会进行字段拷贝操作,两个操作加起来才是真正与装箱互反的操作。

步骤:
1. 如果引用为null,抛出NullReferenceException。
2. 如果目标不是已装箱的值类型,抛出InvalidCastException。
3. 返回指向包含在已装箱对象中值类型部分的引用,而不是重新在堆栈建立值类型实例,因此需要GC回收才能释放。


栈(stack)
------------
位于常规内存区(general random-access memory),处理器可以通过栈指针(stack pointer)对它进行直接访问。指针向下移动创建新的存储空间,向上释放存储空间。是仅次于寄存器(registers)的最快、最有效率的分配内存方法。一般用来存储那些已知大小的值类型和引用,栈中分配的数据在超出作用域后自动被释放。


堆(heap)
------------
这是一段多用途内存池(general-purpose pool of memory)。堆的优点是分配内存时编译器无需知道该分配多少空间,以及数据的生存期。在堆中分配的对象必须通过垃圾回收期回收后才能释放,因此效率要比栈低一些。

 

作者:SamWang
出处:http://wangshenhe.cnblogs.com/
本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。

posted on 2012-05-21 14:26  SamWang  阅读(1546)  评论(0编辑  收藏  举报