飞道的博客

C#值类型、引用类型(堆和栈)

283人阅读  评论(0)

栈和堆

(栈的内存是自动释放的,堆内存是.NET中会由GC来自动释放)

栈(Stack)

  • 栈是一种只能先进后出的内存结构。
  • 存放函数的参数、局部变量、返回数据等值,由编译器自动释放
  • 栈只能在一端对数据进行操作,也就是栈顶端进行操作。
  • 栈也是一种内存自我管理的结构,压栈自动分配内存,出栈自动清空所占内存
  • 栈中的内存不能动态请求,只能为大小确定的数据分配内存,灵活性不高,但是栈的执行效率很高
  • 栈的可用空间并不大,所以我们在操作分配到栈上的数据时要注意数据的大小带来的影响

堆(Heap)

  • 在c里面叫堆,在c#里面其实叫托管堆。托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。
  • 相比栈只能在一端操作,堆中的数据可以随意存取。
  • 能存储大量数据,而且堆能够动态分配存储空间
  • 但堆的结构使得堆的执行效率不如栈高,而且不能自动回收使用过的对象

概念

值类型直接存储其值,而引用类型存储对其值的引用

  • 值类型派生自 System.ValueType,System.ValueType又派生自System.Objcet
  • 引用类型派生自 System.Objcet

值类型:

byte,short,int,long,float,double,decimal,char,bool 和 struct 统称为值类型。
(decimal 关键字指示 128 位数据类型。 与浮点型相比,decimal 类型具有更高的精度和更小的范围,这使它适合于财务和货币计算。)

引用类型:

string 和 class、interface、delegate 、Dynamic 、Object 、数组统称为引用类型。
数组(派生于System.Array)

值类型特点

  • 值类型变量声明后,不管是否已经赋值,编译器为其分配内存。

  • 值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。例如:数组中的元素,引用类型中的值类型的字段,迭代器中的局部变量、闭包情况下匿名函数(lamda)中的局部变量。这些如果值类型分配在线程栈上,有可能出现线程栈中的方法已经调用结束,但是还会访问这些值的情况,可能随着被调用方法的返回而被清除掉。

引用类型特点

  • 引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
  • 引用类型的对象总是在进程堆中分配(动态分配)。

例子

实际上,对于数组:
TestType[] testTypes = new TestType[100];
如果TestType是值类型,则会一次在托管堆上为100个值类型的元素分配存储空间,并自动初始化这100个元素,将这100个元素存储到这块内存里。
如果TestType是引用类型,则会先在托管堆为testTypes分配一次空间,并且这时不会自动初始化任何元素(即testTypes[i]均为null)。等到以后有代码初始化某个元素的时候,这个引用类型元素的存储空间才会被分配在托管堆上。

区别

相同点:

  • 引用类型可以实现接口,值类型当中的结构体也可以实现接口;

  • 引用类型和值类型都继承自System.Object类。

1)范围方面

  • C#的值类型包括:结构体(数值类型、bool型、用户定义的结构体),枚举,可空类型。

  • C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。

2)内存分配方面:

  • 数组的元素不管是引用类型还是值类型,都存储在托管堆上。

  • 引用类型在栈中存储一个引用,其实际的存储位置位于托管堆。简称引用类型部署在托管推上。而值类型总是分配在它声明的地方:作为字段时,跟随其所属的变量(实 例)存储;作为局部变量时,存储在栈上。(栈的内存是自动释放的,堆内存是.NET中会由GC来自动释放)

3)适用场合

  • 值类型在内存管理方面具有更好的效率,并且不支持多态,适合用做存储数据的载体;引用类型支持多态,适合用于定义应用程序的行为。

  • 引用类型可以派生出新的类型,而值类型不能,因为所有的值类型都是密封(seal)的;

  • 引用类型可以包含null值,值类型不能(可空类型功能允许将 null 赋给值类型,如 int? a = null; );

  • 引用类型变量的赋值只复制对对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。

  • 值得注意的是,引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即 直接继承System.ValueType。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较


转载:https://blog.csdn.net/qq_32175379/article/details/116903015
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场