编译器如何强制堆栈内存是连续的,它是否会在程序运行时每次都移动内存,还是在运行之前保留程序所需的堆栈内存?
答案 0 :(得分:25)
给定线程的堆栈在虚拟内存中通常是连续的(在Linux和类似系统上,在Windows中的用户模式下)。 Windows kernel (in Windows Vista and above)和z/OS允许虚拟内存中不连续的堆栈和GCC 4.6 will also allow that。编译器根本不需要移动堆栈,即使对于堆栈具有不连续虚拟地址的系统也是如此;他们只是改变了新零件的分配地点。操作系统可能会将物理页面重新映射为虚拟页面,因此堆栈在物理内存中可能不是连续的,即使它位于虚拟内存中。
答案 1 :(得分:7)
没有要求堆栈在OS或硬件语言中连续。
我挑战任何人站点明确说明这是一项要求的参考。
现在很多实现都使用连续内存,因为它很简单。这也是如何向CS学生传授堆栈概念(堆栈增长堆积扩大)。但是没有要求这样做。我相信MS甚至尝试将堆栈帧放置在堆中的随机位置,以防止使用故意堆栈粉碎技术的攻击。</ p>
堆栈的唯一要求是链接帧。因此允许堆栈在输入/离开范围时推/弹框架。
编译器不会尝试强制堆栈处于连续内存中。语言级别没有要求堆栈连续的要求。
如果这是问题。然后,您将从社区获得更详细和准确的答案。
答案 2 :(得分:4)
你有你的内存地址空间,假设它从1到100运行。你从1向上分配你的堆栈,你从100向下分配你的堆。好到目前为止?
由于堆栈的本质,它总是紧凑的(没有孔)。发生这种情况是因为堆栈中的所有内容都是被调用的某个函数的上下文。每当函数退出时,其上下文将从堆栈顶部移除,我们将回退到上一个函数。我想如果你得到一个调试器并且只是按照函数调用,你就可以理解它,同时记住堆栈必须如何。
另一方面,Heap的表现并不是很好,假设我们已经为堆保留了70到100的内存。我们可以在那里分配一个4字节的块,它可能从70到74,然后我们分配4个字节,现在我们分配了70到78的内存。但是该内存可以在程序的任何一点解除分配。因此,您可以释放在开头分配的4个字节,从而创建一个空洞。这就是你在地址空间中发生的事情。内核保留了一个表,它将页面从地址空间映射到实际内存中的页面。正如您可能已经注意到的那样,当您运行多个程序时,您不可能希望能够很好地设置所有内容。所以内核做的是让每个进程认为整个地址空间是连续的内存(现在不要考虑内存映射设备),即使它可能在内存中非连续映射。
我希望对这个主题有一个合理的概述,但可能比我更好的作者,你可能会喜欢阅读更多。因此,在虚拟内存上查找文本,这可能是您理解所需内容的一个很好的起点。有几本书会用更多或更少的细节来描述它。我所知道的一些:结构化的计算机组织,由tanenbaum;操作系统概念,由Silberschatz。我很确定Knuth也会在他的算法书中讨论它。如果您有冒险精神,可以尝试在英特尔手册上阅读x86实现。