关于堆栈

每次看到这篇博客的时候,都能想到之前面试被怼的经历。面试官最后总结出来一句话:你总是知其然不知其所以然!太浮于表面了。今天的面试就到这里了,你还有什么想问的吗~~

确实,了解一项知识或者技术之前首先应该明确:

  1. 它是什么?
  2. 它为什么会出现(或者说它解决了什么)?
  3. 我们要怎么去使用它?

堆和栈到底是什么?

首先栈和堆(托管堆)都存在于进程的虚拟内存中。栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域。
堆(Heap)是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的。

栈Stack
可以将栈想象成一堆从顶向下堆叠的盒子(如下图左边),当每调用一次方法时,我们将应用程序中所要发生的事情记录在栈顶的一个盒子中,而我们每次只能够使用栈顶的那个盒子。当我们栈顶的盒子被使用完之后,或者说方法执行完毕之后,我们将抛开这个盒子然后继续使用栈顶上的新盒子

  1. 栈中存储值类型。
  2. 栈上是向下填充的,数据只能从栈的顶端插入和删除(先进后出原则)。把数据放入栈顶称为入栈(push),从栈顶删除数据称为出栈(pop)
  3. 栈是自行维护的,也就是说内存自动维护栈,当栈顶的盒子不再被使用,它将被抛出。
  4. 栈的空间较小,但访问速度快

堆栈
堆Heap
堆不分先进后出还是先进先出,堆没有任何访问限制(上图右),它就像是你的书架,所有的书都排列在书架上,当你想看某一本书的时候,可以随时找到一本我们需要的书,从书架上把它拿下来。
而栈就像一串糖葫芦,你总是会先吃到最上面那个山楂(如果你习惯从下面开始吃的话当我没说-.-)

  1. 堆(也叫做托管堆)存储引用类型。
  2. 堆受垃圾处理器GC管理
  3. 堆没有访问限制
  4. 堆的空间较大,但访问速度没有栈快

这里要说一下引用类型存储在堆里其实并不全面,引用类型的本身储存在堆里面,引用地址则储存在栈里。就像上面说的书架:
书架里面有很多本书,引用类型的对象本身就相当于书,而引用地址就像是一个指向(比如第三排从左往右数第3本),它指明了某本书在书架的具体位置,这样我们就可以根据这个指向轻松的拿到书了。
如果还不理解的话

//a代表 最适合c#入门的书
string a = "C# 7.0 in a Nutshell";

//b代表 学c#必看的书
string b = a;

上面声明引用类型变量a和b的时候究竟发生了什么呢:
首先第一句声明a的代码:“C# 7.0 in a Nutshell"被存储在堆里面,并生成一个指向它的地址保存在栈里面。
第二句又声明了一个变量b,这里的 b = a其实就是把a存储在栈里的引用地址复制了一份给了b,而对应的值C# 7.0 in a Nutshell还是只有一份。

堆和栈的清理:
栈是自上往下压入,使用时从上往下依次去拿,所以栈里的数据就像是弹夹里的子弹,打完就没了。(内存会自动清理掉已使用过的数据)
而堆则是由GC进行管理:垃圾收集器的基本算法很简单

  1. 将所有的托管内存标记为垃圾
  2. 寻找正被使用的内存块,并将他们标记为有效
  3. 释放所有没有被使用的内存块
  4. 整理堆以减少碎片

也就是说,当需要清理内存的时候,GC会去找那些很久没有引用地址指向的内存块,把它们清理掉。

为什么要有堆栈(或者说它解决了什么)?

栈:为了存放运行时的局部变量,参数,返回数据,返回地址等。
堆:栈的性能非常高,但是对于所有的变量来说还不太灵活,而且变量的生命周期必须嵌套。
通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段时间内数据仍然可以使用。此时就要用到堆(托管堆)。

  • 68
    点赞
  • 201
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值