如果堆是动态的,那么为什么它被放置在堆栈和数据区域之间

If Heap is dynamic then why it is placed in between stack and data area

提问人:Tarun Mendu 提问时间:8/18/2023 最后编辑:BarmarTarun Mendu 更新时间:8/24/2023 访问量:64

问:

我目前正在学习操作系统,并对此感到震惊。

  • 如果堆区域的大小是动态的,那么为什么它被放置在堆栈的底部。

  • 如果堆的大小增加,堆栈的起始内存(如图中的MAX_SIZE)也会增加到更高的地址以容纳堆的空间,或者限制使用堆栈和数据区域之间的空间。

Memory layout

PS:我在网上搜索了这个,但没有找到我要找的东西。

Linux 管理 操作系统 堆内存 堆栈内存

评论

0赞 trincot 8/18/2023
没有更高的地址可用。请参阅图中的“MAX”:它是可用于进程的内存的末端。如果堆内存和堆栈内存已消耗所有可用内存,则属于内存不足情况。
1赞 Barmar 8/18/2023
无论你把它放在哪里,它最终都会进入其他内存区域或内存的尽头。
0赞 Dave S 8/18/2023
堆和堆栈之间的图片中的蓝色区域在程序分配之前不会映射到任何物理内存,或者在进程读取或写入它之前可能不会映射到任何物理内存。由于堆栈向下增长,因此将其放置在进程地址空间的最顶部是有意义的。
3赞 Barmar 8/18/2023
我想你误解了图表。堆和堆栈都是动态增长的。堆向上增长,堆栈向下增长。如果它们碰到对方,你就没记忆了。
1赞 user17732522 8/18/2023
这也是一个非常幼稚的观点。它不会像现代操作系统上的图表中那样简单。特别是,出于安全原因,现代操作系统尝试随机化堆栈、堆和其他段的地址。此外,如图所示的“堆”只是用于动态分配的内存的一小部分,通过 linux 上的 syscall 实现。例如,通过以下方法获得更大的内存区域 在 Linux 上。而且你真的不需要关心堆栈/堆的位置来编写你的程序。sbrkmmap

答:

0赞 user123 8/24/2023 #1

堆栈由操作系统指定固定大小。编译时,指令会用完堆栈,并且在编译过程中已经知道堆栈内存使用情况。例如,如果输入一个具有 2 个 64 位变量的函数,则编译器会通过生成访问指令(反之亦然)来保留 8 个字节的堆栈。决定堆栈在虚拟内存中的位置的只是操作系统为 STACK_POINTER 选择的值。mov STACK_POINTER, SOME_DATAmov STACK_POINTER - 8, SOME_DATA

特定函数使用的堆栈数量是已知的,因此您的工作是确保堆栈不会被过度使用,因为它的大小有限。

对于堆,访问是绝对的,并且地址由操作系统通过查看可用的虚拟内存页来动态选择。就 cpu 指令而言,它只是一个寄存器,用于存储对操作系统进行的系统调用的返回。应用程序进行系统调用,当系统调用返回时,程序中的进一步指令假定相应的寄存器包含用于数据存储的可用地址,或者可能包含错误代码。

由于使用了分页,因此虚拟地址空间具有数十万 GB 的可用空间。就可以分配的数据量而言,这取决于虚拟内存与物理内存的关联可以延迟多少。只要您实际上不写入动态(堆)虚拟内存,操作系统甚至不必将区域(页面)与物理位置相关联。这是因为该内存区域未被修改,因此它不包含任何需要跟踪的有价值内容。因此,只要操作系统不包含有价值的东西,它就可以延迟其与物理内存的关联。一旦完成,操作系统必须将其保留在某个地方(RAM或SWAP)。因此,可以肯定地说,当您拥有超过 ram + 交换的初始化/有价值数据时,操作系统的空间已经用完,并且可能会通过拒绝进一步分配、终止应用程序或其他方式做出反应。

总之,虚拟地址空间是如此之大,以至于操作系统在堆与堆栈相遇之前就耗尽了空间。如果是这样,那么您的计算机已经用完了数千次空间,并且操作系统不允许您去那里。