4

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

4

2 回答 2

6

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

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

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

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

脚注

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

于 2021-01-10T16:37:39.030 回答
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 faster than Stack Allocation和这篇关于Compiling with Continuations and LLVM 的论文可能会让您感兴趣,两者都与您的问题非常相关:有时,几乎“没有调用堆栈”,“增加它”是没有意义的。

于 2021-01-10T16:42:28.423 回答