是否随作用域分配和解除分配堆栈帧

Are stack frames allocated and deallocated with scope?

本文关键字:解除分配 堆栈 分配 作用域 是否      更新时间:2023-10-16

继上一个问题之后,我一直在查看VS2015代码分析的输出,并在函数中看到高堆栈使用率的警告,该警告可以简化如下;

class base
{
public:
   virtual void Process();
   Buffer[10000];
};
class derived1 : public base
{
public:
   void Process();
}
class derived2 : public base
{
public:
   void Process();
}
void MyFunc(int x)
{
   switch(x)
   {
     case 0:
     {
       derived1 x;
       x.Process();
     } break;
     case 1:
     {
       derived2 y;
       y.Process();
     } break;
   }
}

分析警告我,我在MyFunc中使用了 20,000 字节的堆栈。 情况是否如此,因为所有堆栈变量都在函数入口时分配并在函数出口时释放,而不是在它们使用作用域构造和破坏时? 只是好奇(但还不够好奇,无法在程序集输出;)中涉水( 这里的相关问题并不能完全给我正在寻找的答案。

堆栈帧分配由编译器自行决定。大多数编译器不会尝试使用大变量隔离本地作用域,但大多数编译器确实提供了像 alloca 或 C99 VLA 这样的工具,可以动态扩展现有堆栈帧。因此,架构问题不太可能发挥作用;这纯粹是实施细节的问题。

您可以将本地作用域括在 lambda 表达式中,以鼓励编译器提供此类隔离:

   switch(x)
   {
     case 0:
     []{
       derived1 x;
       x.Process();
     }(); break;
     case 1:
     []{
       derived2 y;
       y.Process();
     }(); break;
   }

尽管如此,没有什么是可以保证的。

您可以使用 godbolt.org 联机编译器查看此类示例的机器代码反汇编。看起来这个技巧适用于 GCC,但在 Clang 上它仅适用于优化-O1或更少,而在英特尔的编译器上它仅适用于 -O0 .