值类型与引用类型
分类索引:C# 语言和运行时剖析--前言
基本概念:
- 值类型是从System.ValueType继承的类型
- 常见值类型包括: 简单数据类型;enum枚举类型;struct结构类型
- 值类型在内存中分配在线程栈上,引用类型在内存中分配在CLR的托管堆上
- 除了值类型之外的数据类型都是引用类型
- 实践中引用类型最常见,但值类型使用得最多
为什么要设计值类型:
- 值类型不需要从托管堆分配
- 引用类型产生的实例对象在托管堆上都会有一些额外的成员,这些成员必须初始化
- 值类型不使用GC垃圾回收控制,作用域结束后,会自行释放。
综上,值类型更有效率,所以在.NET中将一些简单的,常用的,内存占用小的对象设置为值类型,大大提高了整个CLR的效率。
装箱与拆箱:
为什么会发生装箱:
因为值类型与引用类型在CLR中的内存管理方式不同,所以当值类型在程序中需要向引用类型转化的时候就会发生装箱。也就是当值类型的实例对象需要在一个程序作用域的场景下,转化成为不从System.ValueType继承的另外一个类型的对象时,装箱就会发生。
装箱有什么危害:
因为设计值类型的本意是为了提升效率。但是当装箱发生时,值类型会转化成为引用类型,这个时候,效率没有得到任何提高。反而因为装箱,拆箱有可能重复多次的发生,反而让效率更受影响。
最佳实践原则
在以下情况满足时,最好考虑将一个类型设定成为值类型: (否则则应该设计为引用类型)
1.类型中不具备会修改类型中字段的成员(属性,方法)。也就是说,这个类型的实例对象的内部最好不要具备会修改实例状态的方法或者属性。
2.类型不需要从别的类型继承,也不会派生出别的类型。
3.类型的实例较小(最好在16个字节以下)。什么概念,如果包含int32类型的字段的话,最好不要超过4个字段。
超过的话,那么这个类型最好不要作为方法的实参传递,也不作为返回的参数类型。
为什么实例不能太大,一方面因为线程栈空间有限,另一方面在参数传递或者返回对象时,值类型的实例都会全部拷贝一份副本传递。而引用类型传递的是引用地址。
相关优秀博文链接:
6个重要的.NET概念:栈,堆,值类型,引用类型,装箱,拆箱
[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
[你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边
[你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途