C# 中堆与栈的浅记
什么是堆和栈?
简言之,堆和栈是驻留在内存中的区域,它们的作用是帮助我们执行代码。在.Net Framework 环境下,当我们的代码执行时,内存中的堆和栈便存储了这些代码,并包含了代码执行所需要的全部信息。
这样说来还是有些抽象,那么,在堆和栈中究竟都保存了些什么呢?概括说来就是四类数据:
1、值类型数据
2、引用类型数据
3、指针
4、指令
下面对上述四类数据做以简单介绍。我们知道,C#中的数据类型分为两种,分别是值类型和引用类型。值类型数据直接在内存中的一个位置存储它们自身的内容(值);引用类型数据在内存中的一个位置存储指向内存中其它某个位置的地址,而在这个地址所指的位置中存储内容(值)。
对于指针,我们在.Net Framework环境中不会显示的使用指针,它们由CLR来管理。指针本身就是一个内存地址,它指向另一个内存位置。它的值就是一个内存地址或者为空(null)。
指令指的就是执行该方法的指令,当方法执行时需要在栈上为之分配空间。
那么,上述四类数据在堆与栈中是如何分配存储的?或者我们还可以把关心的范围再缩小一下,值类型数据与引用类型数据,它们是如何分配的?
规则:
1、引用类型数据总是存放在堆中;
2、值类型数据如果在方法体中被声明,那么它将存放在栈上;如果它作为引用类型的成员被声明,那么它将存放在堆中。
结合上面的两条规则,让我们分别来看一下堆与栈的不同之处。
在内存中,栈负责保存代码执行的路径(调用路径)。当我们的代码开始调用一个方法时,首先将放置一段编码指令到栈上,接下来再放置方法的参数,然后当代码执行到方法体中声明变量的位置,这些变量将被进栈至栈顶(注意,这里指的是值类型数据,第一种情况)。截止到这里,在方法体中被声明的值类型数据,它们被存放在了栈上。当方法执行完成,方法的结果被返回,此时所有在栈上的该方法所使用的内存空间都被清空,程序将自动回到栈上最初方法调用的位置。这也告诉了我们一点,栈是自行维护的,内存自动维护栈,不存在垃圾回收问题。
第二种情况,当代码执行到在方法体中被声明的引用类型数据的位置,引用类型数据将在堆上被创建,与此同时在栈上生成一个指向这个堆的指针,这个指针就存放在栈上。当方法执行结束后,栈上的相关信息被清除,但是,此时将剩下孤独的引用类型数据参数在堆中,这就是垃圾回收产生的原因。注意,垃圾回收是非常耗费性能的,这就是为什么我们要特别注意栈和堆的使用的原因。
以上内容是自己对于C#之中堆与栈的一个基本而又浅显的理解,后续还会继续深入思考,继续挖掘堆与栈的内容。
C# 中堆与栈的浅记