值类型和引用类型
CLR(公共语言运行时)支持两种类型:值类型和引用类型。
引用类型总是从托管堆上分配,C#中new操作符返回的就是对象位于托管堆中的内存地址------该地址指向对象占用的数据位。
使用引用类型时,我们要注意以下几个事实:
- 内存必须由托管堆分配;
- 每一个托管堆中分配的对象都有一些与之关联的额外附加成员被初始化;
- 从托管堆中分配对象可能会导致执行垃圾收集;
所以说引用类型的性能是比较低的,为了提高那些简单操作,常用类型的性能,CLR提供了值类型,值类型通常分配在线程的对战上(虽然他们也可以被嵌入到一个引用类型中的对象中,注:这时他们也分配在托管堆中)。表示值类型实例变量不包含指向实例的指针------变量本身即包含了实例的所有字段,因为变量本身包含了实例的所有字段,所以操作实例时也就无需解析指针引用。值类型实例不受垃圾回收器的控制,因此也减少了托管堆的压力,以及应用程序在整个生存期中需要垃圾回收的次数。所有的值类型都必须继承自System.ValueType;
线程堆栈和托管堆栈的区别
线程堆栈(Thread Stack):所有值类型的变量都是在堆栈中分配的。
每个正在运行的程序都对应着一个进程(process),在一个进程内部,可以有一个或多个线程(Thread),每个线程都一块“自留地”,成为“线程堆栈”,大小为1M,用于保存自身的一些数据,比如函数中第一的局部变量、函数调用时传递的参数值等,这部分内存区域的分配和回收不需要程序员干涉。
托管堆(heap):所有引用类型变量所引用的对象,其内存都是在托管堆中分配的。
在.Net这种托管环境下,堆由CLR进行管理,所以又成为”托管堆(managed heap)“。托管堆中的内存资源是可以动态申请并使用的,但是用完了必须归还;
值类型和引用类型区别代码
//引用类型 class SomeRef { public int x; } //值类型 struct SomeVal { public int x; } static void Main(string[] args) { SomeRef r1 = new SomeRef();//分配在托管堆上 SomeVal v1 = new SomeVal();//分配在堆栈上 r1.x = 5;//解析指针 v1.x = 5;//在堆栈上修改 //该赋值过程如图一 Console.WriteLine(r1.x);//5 Console.WriteLine(v1.x);//5 SomeRef r2 = r1;//仅仅拷贝指针,这个时候r2和r1是指向同一快内存的 SomeVal v2 = v1;//现在堆栈上分配,然后拷贝成员 //该赋值过程如图二 Console.WriteLine(r1.x);//8 Console.WriteLine(r2.x);//8 Console.WriteLine(v1.x);//9 Console.WriteLine(v2.x);//5 } r1.x = 8;//改变了r1.x和r2.x v1.x = 9;//改变了v1.x没有改变v2.x
图一

图二

以上代码中SomeVal v1=new SomeVal();,该行代码编写的方式看起来很像在托管堆上分配了一个SomeVal实例,然而C#知道它是一个值类型,因此会分配到线程的堆栈上。
值类型不能被继承,不能定义虚方法,不能定义抽象方法。
值类型之间的赋值是”字段对字段“的拷贝;引用类型之间只是引用的拷贝,指向同一块内存。

浙公网安备 33010602011771号