c# 值类型和引用类型 笔记
参考以下博文,我这里只是笔记一下,原文会更加详细
值类型和引用类型
红色表示——“这啥?”(真实1个问题引出3个问题)
CLR支持的两种类型
引用类型:
引用类型从托管堆上分配,new操作符会返回对象的指针——指向对象数据的内存位置的一个引用,引用类型传递的是对象的指针(string特殊)。引用类型的变量都需要一次堆内存的分配。
值类型:
值类型一般在线程栈上分配,一个值类型变量包含了其实例的值,没有引用指针。
相同点:
都是System.Object的子类。
值类型也可以继承接口。
不同点:
1、 值类型分配在堆栈上,引用类型在托管堆上分配;
如果一个引用类型的某个属性是值类型,这个值类型也分配在托管堆上。
2、 所有的值类型都是隐式密封的(sealed),不能继承。
3、 值类型的赋值逐字段的复制,频繁赋值也会造成性能上的压力;引用类型的赋值只是指针传递。
4、 引用类型额外有类型对象指针和同步块索引。
5、 值类型继承自System.ValueType;引用类型继承自System.Object,System.ValueType也继承自System.Object。System.ValueType重写了Equals和GetHashCode方法
性能:
值类型分配在栈上,在GC控制外,不会对GC造成压力;
引用类型分配在堆中,会影响到GC,每一次到堆的内存分配都有可能进行一次垃圾收集操作。
装箱拆箱:
装箱是将值类型转化为引用类型,拆箱则是将引用类型转化为值类型。
装箱:
1、 在托管堆中分配好了内存,分配的内存量为值类型的各个字段需要的内存量加上托管上对象的两个额外成员(类型对象指针,同步块索引)需要的内存量
2、 值类型的字段复制到新分配的堆内存中。
3、 返回对象的地址,这个地址就是这个对象的引用。
拆箱:
1、 获取已经装箱的值类型实例的指针。
2、 把获取到的值复制到栈。
(拆箱只能还原为原先未装箱之前的类型)
装箱比较耗费性能,还可能引起GC操作