函数和变量范围所需的总堆栈大小如何相关?
Posted
技术标签:
【中文标题】函数和变量范围所需的总堆栈大小如何相关?【英文标题】:How is total stack size required by a function and variable scope related? 【发布时间】:2013-05-11 21:57:44 【问题描述】:我在使用 Visual Studio 2010 编译的程序中遇到堆栈溢出。我有一个宏,它在 do-while 块中使用分配在堆栈上的小 char 数组 (8 KiB) 执行一些与字符串相关的工作.然后我有一个函数,我在同一范围内多次使用这个宏。现在我的堆栈溢出了。
我假设堆栈分配是 do-while 块的本地分配,因此当块结束时,数组将不复存在,因此不会影响函数的整体堆栈使用,但看来我错了.
使用调试器,我可以看到在输入函数时调用了 _chkstk()。作为该函数的参数,堆栈大小略大于该函数中每次调用宏的所有 8 KiB 数组的总和(由于其他局部变量而略大)。
我用一个简单的例子重现了这个问题:
void func(void)
char a[500000];
char b[500000];
char c[500000];
char d[500000];
char e[500000];
在简单的控制台应用程序中,从 main() 调用此函数将导致堆栈溢出。但是,删除除一个块语句之外的所有语句都可以正常运行。
我想知道这是否按预期工作?
如何计算函数所需的总堆栈大小? 如何计算函数所需的堆栈大小? 即使超出范围,堆栈上的数组仍然会影响函数的总堆栈大小?
为什么当我遇到堆栈溢出时
【问题讨论】:
由于别名,您不能为嵌套块中的变量重用内存:ideone.com/z9HQUU @millimoose 这是未定义的行为,因此它是无关紧要的,因为编译器可以优化它。 C 标准允许编译器为函数内的一个块范围内的大型分配回收堆栈空间,但它不要求 它。在函数中重用堆栈空间比你想象的要难,所以很多编译器不这样做。但是,我有点惊讶VS2010没有这样做,因为它非常擅长内联,并且您需要重用堆栈空间才能很好地进行积极的内联。你确定你开启了所有的优化? @rightfold 你是对的,在对示例进行了更多研究后,发现空间可以重复使用:ideone.com/rnFYp4。我的错。 在 C++ 中拥有一个依赖堆栈char
数组来执行 “字符串相关工作” 的宏确实闻起来像是一个糟糕的设计决策。您宁愿为此使用动态分配,而使用std::string
可以很好地完全抽象出所有这些问题。
【参考方案1】:
我很确定标准并没有明确定义这些变量需要多少堆栈空间(或者实际上它们存储在堆栈上)。编译器当然不需要为这些局部变量中的每一个分配空间。实际重用也可能高度依赖于编译器的优化级别 - 因此,如果您使用不同级别的优化进行编译(或者如果您启用/禁用某些优化功能),它可能会做不同的事情。
在 C++ 中,对包含变量的块定义了对构造函数和析构函数的调用,因此如果您要使用 std::vector
,则在块结束时释放内存(从堆中分配)。
总而言之:空间可以重复使用,但绝不保证。
【讨论】:
std::vector
在堆中为其元素分配内存,而不是在堆栈中。所以无论如何它不会导致堆栈溢出。
@Inspired:是的,我刚刚进行了编辑以澄清这一点,但我并不是说堆栈空间被重用,只是“构造函数中发生的任何事情都被析构函数撤消,这两者都发生了在包围变量的大括号集中。【参考方案2】:
我想这是特定于编译器的。同样适用于 GCC:数组在超出范围后从堆栈中删除(但当所有数组属于同一块时,它会引发段错误)。
【讨论】:
以上是关于函数和变量范围所需的总堆栈大小如何相关?的主要内容,如果未能解决你的问题,请参考以下文章