前言:今天我们着重讲解.Net下的栈(Stack)和托管堆(Heap)(简称堆)。如果你想提高程序性能,理解栈和堆,那学习这块更是必须的!
文章目录
一、C#中的值类型和引用类型
在讲堆与栈之前,我们先看看值类型和引用类型,这样更能帮助我们理解堆与栈。
通过上面这个表格,我们可以看到,类型被分为两种:值类型(基本数据类型、枚举类型、结构类型)和引用类型(类、接口、数组)。
下来,我们进行简单理解:
- 值类型只需要一段单独的内存,用于存储实际的数据(单独定义的时候放在栈中)。
- 引用类型需要两段内存。
- 第一段存储实际的数据,它总是位于堆中。
- 第二段是一个引用,指向数据在堆中的存放位置。
1、值类型与引用类型的存储方式
- 值类型:值类型总是分配在它声明的地方,做为局部变量时,存储在栈上;类对象的字段时,则跟随此类存储在堆中。
- 引用类型:引用类型存储在堆中。类型实例化的时候,会在堆中开辟一部分空间存储类的实例。类对象的引用还是存储在栈中。
2、通过一个案例理解一下
// 值类型,保存在栈中
int num = 100;
// 引用类型,保存在堆中
int[] nums = {1,2,3,4,5};
// 接下来,我们输出一下
Console.WriteLine(num);
Console.WriteLine(nums);
通过上面这个例子,我们可以看到,num为值类型,所以它直接输出了值,而我们的nums为引用类型,它无法直接输出值,而是输出了一个引用。
3、值类型与引用类型的区别
- 值类型与引用类型都继承自Systerm.Object类。不同之处,几乎所有的引用类型都是直接从Systerm.Object继承,而值类型则是继承Systerm.Object的子类Systerm.ValueType类。
- 我们在给引用类型的变量赋值的时候,其实只是赋值了对象的引用;而给值类型变量赋值的时候是创建了一个副本(说通俗点,就是克隆了一个变量)。
二、堆与栈简单理解
C#程序在CLR上运行的时候,内存从逻辑上划分两大块:栈,堆。这俩基本元素组成我们C#程序的运行环境。
1、堆与栈概念介绍
堆:在c里面叫堆,在c#里面其实叫托管堆。
栈:就是堆栈,因为和堆一起叫着别扭,就简称为栈。
2、托管堆
托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。
3、内存堆栈与数据堆栈
- 内存堆栈:存在内存中的两个存储区(堆区,栈区)。
- 栈区:存放函数的参数、局部变量、返回数据等值,由编译器自动释放。
- 堆区:存放着引用类型的对象,由CLR释放。
- 数据堆栈:是一种后进先出的数据结构,它是一个概念,主要是栈区。
三、堆与栈区别分析
栈通常保存着我们代码执行的步骤,如一个值类型的变量的初始化或者一个方法的声明。而堆上存放的则多是对象,数据等。我们可以把栈想象成一个接着一个叠放在一起的盒子。当我们使用的时候,每次从最顶部取走一个盒子。同样,我们的栈也是如此,当一个方法(或类型)被调用完成的时候,就从栈顶取走,接着下一个,这也就是我们常说的 “先进后出” 。堆则不然,像是一个仓库,储存着我们使用的各种对象等信息,当我们需要调用的时候,会去里面自行寻找并调用。跟栈不同的是它们被调用完毕不会立即被清理掉。
注意:栈内存无需我们管理,也不受GC管理。当栈顶元素使用完毕,立马释放。而堆则需要GC(Garbage Collection:垃圾收集器)清理。
四、堆与栈存储讲解
我们把内存分为堆空间和栈空间,区别如下:
- 栈空间比较小,但是读取速度快。
- 堆空间比较大,但是读取速度慢。
1、栈的深入讲解
栈(Stack)最明显的特征就是“先进后出”,本质上讲堆栈也是一种线性结构,符合线性结构的基本特点:即每个节点有且只有一个前驱节点和一个后续节点。栈把所有操作限制在"只能在线性结构的某一端"进行,而不能在中间插入或删除元素。我们把数据放入栈顶称为入栈(push), 从栈顶删除数据称为出栈(pop)。
2、堆的深入讲解
堆(Heap)是一块内存区域,与栈不同,堆里的内存能够以任意顺序存入和移除。
五、GC(Garbage Collection)垃圾收集器介绍
CLR的GC就是内存管理机制,我们写程序不需要关心内存的使用,因为这些都是CLR帮我们做了。