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