为什么C++程序会为局部变量分配比最坏情况下更多的内存?

sha*_*oth 9 c++ stack-overflow compiler-construction memory-management visual-c++

灵感来自这个问题.

显然在以下代码中:

#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    if( GetTickCount() > 1 ) {
        char buffer[500 * 1024];
        SecureZeroMemory( buffer, sizeof( buffer ) );
    } else {
        char buffer[700 * 1024];
        SecureZeroMemory( buffer, sizeof( buffer ) );
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用Visual C++ 10进行编译时使用默认堆栈大小(1兆字节),并在(/ O2)上进行优化,因为程序试图在堆栈上分配1200千字节而发生堆栈溢出.

上面的代码当然有点夸大以显示问题 - 以相当愚蠢的方式使用大量堆栈.然而在实际场景中,堆栈大小可以更小(例如256千字节),并且可能有更多分支具有更小的对象,这将导致总分配大小足以溢出堆栈.

这是没有意义的.最糟糕的情况是700千字节 - 它将是构建一直具有最大总大小的局部变量集的代码路径.在编译期间检测该路径应该不是问题.

因此编译器会生成一个程序,尝试分配比最坏情况更多的内存.根据这个答案, LLVM也是如此.

这可能是编译器的一个缺陷,或者可能有一些真正的理由这样做.我的意思是也许我只是不明白编译器设计中的某些东西可以解释为什么以这种方式进行分配是必要的.

为什么编译器希望程序在最坏的情况下分配比代码需要更多的内存?

Cli*_*ton 1

以下代码在ideone上使用 GCC 4.5.1 编译时将两个数组放置在同一地址:

#include <iostream>

int main()
{
  int x;
  std::cin >> x;

  if (x % 2 == 0)
  {
    char buffer[500 * 1024]; 
    std::cout << static_cast<void*>(buffer) << std::endl;
  }

  if (x % 3 == 0)
  {
    char buffer[700 * 1024]; 
    std::cout << static_cast<void*>(buffer) << std::endl;
  }
}
Run Code Online (Sandbox Code Playgroud)

输入:6

输出:
0xbf8e9b1c
0xbf8e9b1c

如果您想要这种优化,答案可能是“使用另一个编译器”。