为什么大多数操作系统在运行时无法增加堆栈?

Oll*_*edt 4 c operating-system stack-allocation

是为了避免碎片化吗?还是其他什么原因?与malloc()手动生命周期相比,内存分配的设置生命周期是一个非常有用的构造。

Eri*_*hil 6

随着函数的调用和返回,用于堆栈的空间在程序执行期间频繁地增加和减少。堆栈允许的最大空间通常是一个固定限制。

在较旧的计算机中,内存是一种非常有限的资源,它可能仍然存在于小型设备中。在这些情况下,硬件能力可能会对最大堆栈大小施加必要的限制。

在具有大量内存的现代系统中,可能有大量内存可用于堆栈,但允许的最大值通常设置为较低的值。这提供了一种捕获“失控”程序的方法。通常,控制程序使用多少堆栈空间是软件工程中被忽略的部分。已经根据实际经验设置了限制,但我们可以做得更好。1

从理论上讲,一个程序可以被赋予一个小的初始限制,如果它发现自己正在处理一个“大”问题,它可以告诉操作系统它打算使用更多。这仍然会捕获大多数“失控”程序,同时允许精心设计的程序使用更多空间。然而,总的来说,我们设计的程序使用堆栈进行程序控制(管理函数调用和返回,以及用于本地数据的适度空间)和用于操作数据的其他内存。所以堆栈空间在很大程度上是程序设计的一个函数(这是固定的),而不是问题的大小。该模型一直运行良好,因此我们继续使用它。

脚注

1例如,对于每个不使用具有运行时可变大小的对象的例程,编译器可以报告例程在通过它的任何路径中使用的最大空间。链接器或其他工具可以报告任何调用树 [因此没有循环] 使用的最大堆栈空间。其他工具可以帮助分析具有潜在递归的调用图中的堆栈使用。


Bas*_*tch 5

为什么大多数操作系统在运行时无法增加堆栈?

这对 Linux 来说是错误的。在最近的 Linux 系统上,每个线程都有自己的调用堆栈(请参阅pthreads(7)),并且应用程序可以(通过巧妙的技巧在通过以下方式查询调用堆栈后使用mmap(2)mremap(2)增加一些调用堆栈/proc/(参见proc(5)并使用/proc/self/maps) 就像pmap(1)那样。

当然,这样的代码是特定于体系结构的,因为在某些情况下调用堆栈会朝着增加地址的方向增长,而在其他情况下则朝着减少地址的方向增长。

另请阅读操作系统:三个简单的部分OSDEV wiki,并研究GNU libc的源代码。

顺便说一句,Appel 的书Compiling with Continuations,他的旧论文Garbage Collection can be fast than Stack Allocation和这篇关于Compiling with Continuations 和 LLVM 的论文可能会让您感兴趣,并且两者都与您的问题非常相关:有时,几乎“没有调用堆栈”而“增加”是没有意义的。