7

如果您编写的应用程序是:

  • 单线程
  • 调用图中没有循环
  • 不使用 alloca 或VLA

现代整个程序优化编译器可以优化所有堆栈分配(例如 GCC、MSVC、ICC)吗?在这种情况下,它似乎应该能够静态分配所有可能的堆栈空间。“整个程序”是指编译器可以访问 /all/ 源代码(在运行时不可能 dlopen 等)。

4

4 回答 4

2

如果您可以保证您所说的条件,那么可以:可以有效地使堆栈完全静态分配。每个函数都有一块堆栈内存。

但是,实际的编译器会这样做吗?不。

这样做绝对没有任何好处。事实上,它可能获得的收益可能会少得可怜。很多时候,大部分工作堆栈都在缓存中,因此对其进行修改非常便宜。如果堆栈在静态内存中,那么任何特定函数的“堆栈”内存将被缓存的唯一时间是您最近调用了该函数。使用真正的堆栈,您更有可能在缓存中工作。

此外,给每个函数一个堆栈内存块可以很容易地使您的程序的静态内存使用量比它需要的大得多。栈是一个固定大小的结构;无论你有多少个函数,堆栈都会占用一定的大小。如果您有 100,000 个函数,并且每个函数占用 64 字节空间,那么您的静态“堆栈”必须占用 ~6.4MB 空间。

为什么?您永远不会在任何时候使用大部分内存。该程序可以在 1MB 甚至 512KB 的堆栈中正常运行;为什么要白白占用 6 倍的内存?

因此,它既不是性能优化,又会使程序的内存膨胀。

于 2012-04-09T16:48:45.867 回答
1

这是一个太长的评论,不能成为评论:

请注意,虽然理论上所有的堆栈分配都可能被优化掉,但分配的数量可能超出了必要的范围。这不是 OP 所要求的,但考虑起来可能很有趣。找到所需的最小大小分配将等同于解决停机问题。想象一个程序结构如下:

<do 'something'>
<call last thing which happens to require more
 stack space than everything else in 'something'>

如果<do 'something'>“停止”,您只需要额外的堆栈空间。

您还可以想象优化变得任意困难的其他变体。例如,您的程序可以简单地使用用户输入评估 3SAT 表达式并根据该输入执行某些操作——但该 3SAT 表达式可能具有也可能没有任何导致 true 的值。

也许还有一个更简单的情况:用户可能根本不会输入需要更多堆栈空间进行处理的输入。

于 2012-04-09T14:24:30.843 回答
1

编译器可以做到这一点,但它可能是一种特定的优化,它可能不会。

如果您有一个完全内联的程序,您将负责为函数调用设置堆栈帧的开销。

但是,如果您还想摆脱局部变量的堆栈分配,编译器必须将这些局部变量转换为全局变量。我所知道的编译器都没有这样做,并且在某些平台上,与局部变量相比,引用全局变量需要额外的指令(因为地址必须加载两条指令而不是一条指令)。另外,由于引用堆栈变量是一种常见的操作,它通常被编码成更小的指令。

于 2012-04-09T20:32:04.343 回答
0

除非您将“不使用任何外部库”添加到列表中,否则对外部函数的任何调用都需要设置堆栈,因为它们会被编译,期望调用代码以特定方式传递其参数,最有可能在堆栈上。此外,这些库几乎肯定必须为自己的本地人调整堆栈。

此外,根据您的精确应用程序,即使您知道可以静态分配堆栈,编译器也可能很难知道您的代码中没有任何回调等,这将导致需要堆栈分配。

我只是看不到编译会尝试这种优化的情况,因为分配堆栈空间已经非常快了(我相信有几个寄存器操作)

于 2012-04-09T15:46:26.053 回答