内存模型为何要同时设计“栈区”与“堆区”?

开发 前端
因为堆的这种顺序结构,导致其在处理庞大的数据排序时具有更好的性能,“堆排序”本身就是一种典型的处理大量数据的选择排序算法。而高效的排序则意味着可以更快地基于有序队列进行高效的查找,进而从整体上提升查找的效率。这就弥补了栈结构在大规模使用,管理过大内存后的性能短板。

如题,还有为啥是栈和堆,而不是队列或者其他什么数据结构?这就是本文要说的。

一、栈与堆简介

在回答上述问题前,先要明确什么是“栈”,什么又是“堆”。所谓栈就是一种一维的“线性表”,而“堆”则是二维的完全二叉树。不难看出栈相比于堆是一种更简单的数据结构,这也是其被用于内存模型的原因之一,够简单,所以其创建成本就很低,进而内存的使用性能就可以提升上去。而堆作为一种完全二叉树,同时具有“顺序结构”的特点,这就让其在处理大量数据的排序时拥有更好的性能。

图片图片

二、栈相比队列的优势

前面说栈结构简单,难免不让人想到队列,相比较起来,队列结构似乎更简单一点,就算没有更简单也绝不比栈复杂,那凭什么不用队列而用栈呢?

队列无法取代栈用作内存模型就是因为它太简单了,“先进先出”的数据结构,就只能先进先出。而栈虽然常被描述为“先进后出”型数据结构,但实际却并非看上去那么简单,而是可以让多个元素在入栈顺序相同的情况下,根据需求产生各种不同的出栈顺序。

图片图片

比如有a、b、c三个元素依次进栈,问出栈顺序是怎样的?依据先进后出的原则,很多人应该马上会想到c、b、a的出栈顺序,其实还可以仍旧是a、b、c的顺序出栈,和入栈顺序是一样的。这是不是违背了“先进后出”原则呢?其实没有。

认为a、b、c的进栈顺序和出栈顺序一样是违背了“先进后出”原则是因为把三个元素捆绑在一起去看了,但是分别去看就会发现并没有违背先进后出。我们可以让a进栈之后立刻出栈,然后b进栈再出栈,最后让c进栈然后出栈,基于此种操作,你就会发现a、b、c的进栈顺序和出栈顺序一样,同时每个元素单独来看仍旧是“先进后出”的。

想得简单一点,栈就是一个口袋,往里面放东西和取东西的顺序自由度是很高的,这就让栈在拥有与队列差不多的简单结构易于被创建的同时,拥有更强大的可操作性。而队列则像是一个垂直悬空放置且没有封堵出口的管道,第一个进去的必然第一个出来,没有其他的可能性,这种过于简单的结构缺乏可操作性,所以落选内存模型的数据结构设计。

三、堆的优势

如果只是管理非常小的内存,栈已经是个足够好的数据结构了,这里说的“小”指的是1M到2M这种规模,而这种规模显然与实际不符,实际的主流内存已经达到8G以上了,那剩下的那些内存如何管理的呢?它们则主要依靠堆结构管理(是主要不是全部)。前面说了堆是一种完全二叉树,也就是除了最后一层外其他层全是满结点的二叉树,而且更重要的是它还是“顺序结构”的。

说堆是一种“顺序结构”的完全二叉树,意思就是说,假如用“中序遍历”对其进行从根到叶子的遍历,将会得到“整体有序”的队列。再说得通俗一点就是,我们知道一棵大的二叉树往往是由若干小的二叉树组合而成的,然后在这样一种结构中,我们会看到里面所有的父结点的值一定都是大于其左、右子结点的,这被称为大根堆。还有一种情况是所有父结点都是小于其左、右子结点的,这被称为小根堆。

图片图片

这时我们会看到堆不光因为其完全二叉树的结构像一个金字塔,其每层的值也是如金字塔一样,从底部开始一层比一层大,直到根节点是最大值,即大根堆。或者从底层开始一层比一层小,直到根节点是最小值,即小根堆。

因为堆的这种顺序结构,导致其在处理庞大的数据排序时具有更好的性能,“堆排序”本身就是一种典型的处理大量数据的选择排序算法。而高效的排序则意味着可以更快地基于有序队列进行高效的查找,进而从整体上提升查找的效率。这就弥补了栈结构在大规模使用,管理过大内存后的性能短板。

四、栈与堆的取长补短

但是堆作为一种相对复杂的数据结构,其创建过程明显比栈复杂,这导致它在处理少量的简单类型数据时,其性能反而不如栈,这里的短板则由栈来弥补。于是内存模型就同时设计了栈与堆,二者配合使用取长补短。

责任编辑:武晓燕 来源: Web学社
相关推荐

2020-03-30 11:10:34

JVM内存结构

2009-06-03 15:52:34

堆内存栈内存Java内存分配

2022-03-16 08:39:19

StackHeap内存

2019-04-09 15:56:46

虚拟机内存区Java

2022-01-07 13:50:55

语言内存代码

2020-03-10 09:30:11

Java内存数据

2022-05-13 09:02:34

LinuxBufferCache

2022-08-31 10:13:04

C语言代码

2010-09-25 12:54:24

JVM内存

2009-06-08 22:01:03

Java堆Java栈区别

2010-03-31 14:20:23

Oracle内存结构

2017-12-18 17:21:56

AndroidJava内存泄漏

2021-03-08 09:00:00

Java编程内存

2012-03-05 14:19:26

Java

2010-02-03 15:11:53

C++内存区域

2011-07-15 01:10:13

C++内存分配

2011-06-21 11:16:24

cc++

2020-05-27 21:13:27

JavaJVM内存

2023-11-01 08:07:42

.NETC#

2010-09-25 14:12:50

Java内存分配
点赞
收藏

51CTO技术栈公众号