我在课本中读到堆栈通过减少内存地址而增长;也就是说,从较高地址到较低地址。这可能是一个糟糕的问题,但我没有把这个概念弄好。你能解释一下吗?
答案 0 :(得分:50)
首先,它取决于平台。在某些体系结构中,堆栈从地址空间的底部分配并向上扩展。
假设x86这样的架构从地址空间的顶部向下扩展,那么这个想法非常简单:
=============== Highest Address (e.g. 0xFFFF)
| |
| STACK |
| |
|-------------| <- Stack Pointer (e.g. 0xEEEE)
| |
. ... .
| |
|-------------| <- Heap Pointer (e.g. 0x2222)
| |
| HEAP |
| |
=============== Lowest Address (e.g. 0x0000)
要增加堆栈,你需要减少堆栈指针:
=============== Highest Address (e.g. 0xFFFF)
| |
| STACK |
| |
|.............| <- Old Stack Pointer (e.g. 0xEEEE)
| |
| Newly |
| allocated |
|-------------| <- New Stack Pointer (e.g. 0xAAAA)
. ... .
| |
|-------------| <- Heap Pointer (e.g. 0x2222)
| |
| HEAP |
| |
=============== Lowest Address (e.g. 0x0000)
正如您所看到的,为了增加堆栈,我们将堆栈指针从0xEEEE减少到0xAAAA,而要增加堆,您必须增加堆指针。
显然,这是内存布局的简化。实际的可执行文件,数据部分......也加载到内存中。此外,线程有自己的堆栈空间。
您可能会问,为什么堆栈会向下生长。好吧,正如我之前所说的,一些架构反过来,使堆向下增长,堆栈向上增长。将堆栈和堆放在相对的两侧是有意义的,因为它可以防止重叠,并且只要有足够的可用地址空间,两个区域就可以自由增长。
另一个有效的问题可能是:程序是否应该减少/增加堆栈指针本身?架构如何将一个架构强加给程序员?为什么它不依赖程序,因为它依赖于架构?
虽然你几乎可以对抗架构并以某种方式在相反的方向上移开你的堆栈,但是一些指令,特别是call
和ret
直接修改堆栈指针将会假设另一个方向,弄得一团糟
答案 1 :(得分:20)
现在很大程度上是因为它已经用这种方式做了很长时间,很多程序都认为它是这样做的,而且没有真正的理由去改变它。
当恐龙在地球上漫游而计算机拥有8kB的内存时,如果幸运的话,这是一个重要的空间优化。你把堆栈的底部放在内存的最顶端,然后逐渐减少,然后将程序及其数据置于最底层,malloc
区域逐渐增长。这样,堆栈大小的唯一限制是程序+堆的大小,反之亦然。如果堆栈开始于4kB(例如)并且长大,那么堆永远不会超过4kB(减去程序的大小),即使程序只需要几百个字节的堆栈。
答案 2 :(得分:0)
Man CLONE:child_stack参数指定子进程使用的堆栈的位置。由于子进程和调用进程可能共享内存,因此子进程不可能与调用进程在同一堆栈中执行。因此,调用进程必须为子堆栈设置内存空间,并将指向该空间的指针传递给clone()。堆栈在所有运行Linux的处理器(HP PA处理器除外)上向下增长,因此child_stack通常指向为子堆栈设置的内存空间的最高地址。
答案 3 :(得分:0)
在x86上,堆栈朝着减少的内存地址增长的主要原因是PUSH
指令减少了堆栈指针:
递减堆栈指针,然后将源操作数存储在堆栈顶部。
请参阅第40页。 Intel® 64 and IA-32 ArchitecturesSoftware Developer’s Manual中的4-511。