目录
C#学习笔记之值类型与引用类型
1.值类型与引用类型
1.1 深层区别
值类型与引用类型有不同的内存分布,这导致了不同的内存管理机制:
- 值类型由OS负责内存管理
- 引用类型由垃圾回收器(GC)负责内存管理
内存管理:指的是对内存的分配与释放的管理
1.2 值类型与引用类型的嵌套使用
1.2.1 引用类型嵌套值类型
eg 1.类的字段值是值类型,它是在托管堆上的。
eg 2.局部变量(如方法中的变量),是在堆栈上的。
1.2.2 值类型嵌套引用类型
堆栈保存了引用,托管堆保存了实际的数据。
1.3 小结
- 由于值类型由OS直接对内存进行管理,而引用类型需要使用托管堆对内存进行管理,所以值类型在性能上有天然的优势;
- 引用类型可以具有继承性(类,接口);
- 使用引用类型进行传参时会改变变量本身(string除外,因为string具有不变形,赋值后不可改变。可以理解为const修饰符修饰的变量?);
- 值类型实例总会被分配到它声明的地方,引用类型总被分配到托管堆上。
2.装箱与拆箱
2.1 类型转换的几种方法
- 隐式的类型转换(装箱);
- 显示转换
- is和as运算符进行安全的类型转换
- .NET类库中的Conver进行类型转换
2.2 什么是装箱与拆箱
graph TD;
值类型-->1装箱;1装箱-->引用类型;引用类型-->2拆箱;2拆箱-->值类型;
值类型-->1装箱;1装箱-->引用类型;引用类型-->2拆箱;2拆箱-->值类型;
值类型装箱成为引用类型,引用类型拆箱成为值类型。
装箱过程:在托管堆生成一份堆栈中值类型对象的备份。
- 内存分配:在托管堆中分配放置赋值的实际数据的空间;
- 完成实际数据的分配:将值类型实例的数据复制到新分配的空间中;
- 地址返回:将托管堆中的对象地址返回给引用类型变量。
拆箱过程:将托管堆中生成的引用类型所指向的已装箱的值类型数据复制到值类型对象的过程。
- 检查实例:是否为null,否则继续检查变量是否和拆箱后的类型是否为同一类型,是继续;
- 地址返回:返回已经装箱变量的实际数据部分地址;
- 数据复制:将托管堆中的数据复制到堆栈中。
2.3 一个装箱与拆箱的例子
int i = 3;
object o = i; // 装箱
int y = (int)o; // 拆箱
2.4 装箱与拆箱带来的问题
- 性能问题
- 中间带有复制操作,会降低性能
- 产生中间对象,造成了GC(垃圾回收器)的负担
- 会产生隐藏的bug
2.5 小结
- 值类型装箱成为引用类型,引用类型拆箱成为装箱前的值类型
- 装箱会在托管堆生成堆栈中值类型对象的备份,根据这个备份可以完成拆箱
- 过多使用装箱与拆箱操作会带来性能问题与产生一些难以排除的bug