为什么我们只有两个数据结构“堆栈”和“堆”?
为什么我们只有两个数据结构“堆栈”和“堆”? 像int值将被存储在堆栈中,并且类似的引用类型值将被存储在堆中。
为什么我们不能使用其他数据结构? 是否有任何特定的原因只使用两个这些堆栈和堆。
非常感谢。
内存分配上下文中的“堆栈”和“堆”不是数据结构。 它们是内存布局方案,可以或不可以用堆栈/堆(分别)实现。
这两种内存布局方案的存在源于对两种不同类型内存的需求:
我们来考虑两种情况:
静态内存分配
首先,想象一下,如果我们处理的函数只是参数和输入,并返回一些值作为输出,并且不使用局部变量。 需要分配内存,以某种方式在函数启动之前存储参数,并在函数存在后存储返回值。 数据结构的自然选择是一个堆栈。 每次调用一个新函数时,都会在一个堆栈(称为运行时堆栈)上分配一个新的堆栈帧,并将参数压入该堆栈。 每当一个函数存在时,它的堆栈框架就会从堆栈中弹出,并且它的返回被推送,以便其调用者可以读取它。
该方案可以扩展为支持局部变量。 根据定义,任何“本地”变量只存在于函数的生命周期中。 正因为如此,它们非常适合,我们可以在函数的堆栈框架中为它们分配空间。
这个堆栈可以以任意数量的方式实现,如连续数组或链表,但最终仍然可以作为堆栈,只能在顶部进行推送/弹出。 该约束是可接受的,因为函数和函数调用的性质如下: - 函数在所调用的所有函数完成之前无法退出。 因此,不需要删除位于堆栈顶部的堆栈框架。 - 只有当前运行的函数可以进行新的函数调用。 因此,不需要在栈顶以外的位置添加栈帧。
动态内存分配
其次,我们有记忆,它需要能够存在一些无限期的持续时间,这并不局限于定义它的函数的生命周期。 这可以通过多种方式完成。 可能有一个连续的数组被拆分并以某种方式进行分配(这最终如何以任何方式工作),它可以是链接列表或树结构。 堆恰好是一种树,但这是巧合。 “堆”这个术语与动态内存分配有关,意思是“一堆”或“堆”,这是一组杂乱无章的事物。
第三种情况
不存在,因为没有第三种选择存储器的生命周期。 它们要么绑定到函数的一生,要么不是。 第三种内存分配方案只有在我们有第三种要求没有被前两种情况所覆盖时才存在。
堆栈是一种数据结构。 堆不是数据结构。 可以在堆中创建堆栈。
事实上,你似乎描述它们的方式,它们是MEMORY ALLOCATION方案。 编程语言使用第三种机制:静态分配。
如果你使用编程语言,堆只是内存。 堆栈只是内存。 唯一使堆栈成为堆栈的是内存最后被分配到最后。 任何内存都可以是一个堆栈。
这听起来像是一些阐述。
可执行文件和共享库文件实际上是指导加载程序执行的程序。 在运行程序时,可执行文件指示加载程序分配内存页面。 该存储器通常是只读的(静态数据),读/写(初始化的程序数据),读/写需求零(静态数据初始化为零,以及读取/执行页面。指定可执行文件创建的块之一作为堆栈,EXE指示加载器将堆栈指针寄存器放置在该块顶部的(靠近)位置。
请注意,程序启动时没有堆。
一旦程序启动,内存管理器可能会执行。 通常程序中只有一个,但可能有多个内存管理器。 这些内存管理器分配成堆的内存读/写页面。
应用程序完全有可能使用内存管理器来分配一块内存,然后使程序堆栈(很少见,但为各种算法分配应用程序堆栈很常见)。
堆栈是一个通用的数据结构。 程序堆栈是由堆栈指针寄存器管理的堆栈。 堆栈本身只是一块读/写内存。
堆只是一个由内存管理器控制的块或读/写内存。 内存管理器肯定会在堆上施加数据结构,但该结构对应用程序不可见。 所有的应用程序都看到页面已被添加到其地址空间。
然后有两个级别的动态内存分配。
内存管理员必须呼叫#1来为#2服务呼叫。 通常,一个是指从内存管理器分配的“动态”内存。
但是,加载到应用程序中的页面也可以是动态的。 程序加载器设置应用程序的初始状态时,应用程序可以通过分配和释放页面来修改其页面布局。 在大多数系统中,应用程序甚至可以释放由应用程序加载器创建的页面(但这很可能导致崩溃)。
总结:1.应用程序可以具有只读,读/写(初始化或要求零)以及读取/执行内存页面。 2.任何页面都可以作为程序堆栈(但最好是读/写)。 3.一个或多个内存管理器可以分配读/写页面并将它们用于堆。
链接地址: http://www.djcxy.com/p/82839.html上一篇: Why we have only two data structure "stack" and "heap"?
下一篇: Java heap terminology: young, old and permanent generations?