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

visual Why would a C++ program allocate more memory for local variables than it would need in the worst case?

本文关键字:情况下 内存 最坏 程序 c++ 局部变量 分配 为什么      更新时间:2023-10-16

受到这个问题的启发。

显然在以下代码中:

#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;
}

在Visual c++ 10 (/O2)上使用默认堆栈大小(1兆字节)编译时,由于程序试图在堆栈上分配1200千字节,因此会发生堆栈溢出。

上面的代码当然稍微夸张了一下,以显示这个问题——以一种相当愚蠢的方式使用了大量的堆栈。然而,在实际场景中,堆栈大小可能更小(如256千字节),并且可能有更多带有较小对象的分支,这将导致总分配大小足以溢出堆栈。

这没有意义。最坏的情况是700千字节——它将是构建局部变量集的代码路径,该代码路径在整个过程中具有最大的总大小。在编译过程中检测该路径应该不成问题。

编译器生成的程序会尝试分配比最坏情况更多的内存。根据这个答案,LLVM也做同样的事情。

这可能是编译器的缺陷,或者可能有一些真正的原因这样做。我的意思是,也许我只是不理解编译器设计中的一些东西,这些东西会解释为什么这样做分配是必要的。

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

我只能推测这个优化被编译器设计者认为太不重要了。或者,可能有一些微妙的安全原因。

顺便说一句,在Windows上,当线程开始执行时,堆栈是保留整个的,但是是根据需要提交的,所以即使你保留了一个大的堆栈,你也不会真正花费太多的"实际"内存。

在32位系统上,保留一个大的堆栈可能是一个问题,在32位系统上,拥有大量的线程可能会占用可用的地址空间,而不会真正提交太多内存。在64位,你是黄金。

这可能取决于您对securezerommemory的使用。试着用常规的zerommemory替换它,看看会发生什么——MSDN页面本质上表明SZM有一些超出其签名所暗示的额外语义,它们可能是bug的原因。

在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;
  }
}

输入:6

输出:0 xbf8e9b1c
0 xbf8e9b1c

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

操作系统分页和字节对齐可能是一个因素。此外,内务管理可能会使用额外的堆栈以及调用该函数内的其他函数所需的空间。

相关文章: