为什么我们只有两个数据结构“堆栈”和“堆”?像int值将存储在堆栈中,类似的引用类型值将存储在堆中。
为什么我们不能使用其他一些数据结构?是否有任何特定的理由只使用这两个堆栈和堆。
非常感谢。
答案 0 :(得分:-1)
“堆栈”和内存分配上下文中的“堆”不是数据结构。它们是内存布局方案,可以或不可以分别使用堆栈/堆来实现。
这两种存储器布局方案的存在源于对两种不同存储器的需求:
让我们考虑两种情况:
首先,假设我们处理的函数只接受参数和输入,并返回一些值作为输出,并且不使用局部变量。需要分配内存,以某种方式在函数启动之前存储参数,并在函数存在后存储返回值。数据结构的自然选择是堆栈。每次调用新函数时,都会在堆栈(称为运行时堆栈)上分配新的堆栈帧,并将参数推送到该堆栈。每当一个函数存在时,它的堆栈帧就会从堆栈中弹出,并且它的返回被推送,以便它的调用者可以读取它。
此方案可以扩展为支持局部变量。根据定义,任何“本地”变量仅存在于函数生命周期的持续时间内。因此,它们非常合适,我们可以在函数的堆栈框架中为它们分配空间。
这个堆栈可以通过多种方式实现,如连续数组或链表,但最终它仍然可以作为堆栈,只能在顶部推送/弹出。由于函数和函数调用的工作原理,该约束是可以接受的: - 在调用的所有函数完成之前,函数无法退出。因此,不需要在位置不在堆栈顶部的位置移除堆栈帧。 - 只有当前运行的函数才能进行新的函数调用。因此,不需要在堆栈顶部以外的位置添加堆栈帧。
其次,我们有记忆需要能够存在一段不确定的持续时间,而这段时间并不限定于定义它的函数的生命周期。这可以通过多种方式完成。可能存在一个连续的数组,它以某种方式分离和分配(这最终是RAM的工作方式),它可以是链表,也可以是树结构。 heap碰巧是一种树,但这是巧合。术语堆,因为它与动态内存分配有关,意思是“束”或“堆”,一组杂乱无章的东西。
不存在,因为内存生命周期没有第三种选择。它们要么与函数的生命有关,要么与它们无关。第三种内存分配方案只有在我们有前三种情况未涵盖的第三项要求时才会存在。
答案 1 :(得分:-2)
Stack是一种数据结构。堆不是数据结构。可以在堆中创建堆栈。
事实上,您似乎在描述它们的方式,它们是MEMORY ALLOCATION方案。编程语言用户第三种机制:静态分配。
如果你落后于编程语言,那么堆只是内存。堆栈只是内存。使堆栈成为堆栈的唯一因素是内存最后一次分配。任何内存都可以是堆栈。
听起来好像有些细节。
可执行文件和共享库文件实际上是指示加载程序执行操作的程序。运行程序时,可执行文件会指示加载程序分配内存页。该存储器通常是只读(静态数据),读/写(初始化程序数据),读/写需求为零(静态数据初始化为零,以及读/执行页)。可执行文件指定要创建的块之一被指定作为堆栈.EXE指示加载器将堆栈指针寄存器放在该块顶部(附近)。
请注意,程序启动时没有堆。
程序启动后,内存管理器可能会执行。通常程序中只有一个,但可能有多个内存管理器。这些内存管理器分配内存的读/写页面。
应用程序完全有可能使用内存管理器来分配内存块,然后将其作为程序堆栈(很少见,但通常会为各种算法分配应用程序堆栈)。
堆栈是通用数据结构。 程序堆栈是由堆栈指针寄存器管理的堆栈。 堆栈本身只是一个读/写内存块。
堆只是由内存管理器控制的块或读/写内存。内存管理器肯定会在堆上强加一个数据结构,但该结构对应用程序是不可见的。所有应用程序都看到页面已添加到其地址空间。
然后有两个级别的动态内存分配。
内存管理员必须拨打#1来拨打#2的电话。通常,一个是指从内存管理器分配的内存为"动态。"
但是,应用程序中加载的页面也可以是动态的。当程序加载器设置应用程序的初始状态时,应用程序可以通过分配和释放页面来修改其页面布局。在大多数系统中,应用程序甚至可以释放由应用程序加载器创建的页面(但这可能会导致崩溃)。
总结: 1.应用程序可以具有只读,读/写(初始化或要求零)以及读取/执行内存页面。 2.任何页面都可以成为程序堆栈(但最好是读/写)。 3.一个或多个内存管理器可以分配读/写页面并将它们用于堆。