我目前正在使用未使用STL容器构建的特定库。在将一些函数重构为类时,我遇到了基于以下模式的堆栈溢出。
class Base
{
float values[1920 * 1080]; // causes overflow
public:
Base() {}
};
int main()
{
float values[1920 * 1080]; // does not
Base t;
}
我知道你可以为Base::values
分配动态内存,但是为什么它不会导致main
中的堆栈溢出,但是在Base
中,为什么堆栈空间看起来要小得多Base
?也许这是显而易见的,我只是缺席了。
(上面使用Visual Studio 2017编译的示例,默认标志)
答案 0 :(得分:0)
1920 * 1080 * sizeof(float)足以吹掉堆栈。 (8 Mb)
确保编译器不通过设置元素来删除值数组。
更改基数如下。
class Base {
float * values;
Base() {
values = new float[1920*1080];
}
~Base(){
delete [] values;
}
}
还修复了复制和赋值运算符。
答案 1 :(得分:0)
如果你这样做:
float values[1920 * 1080];
您正在将浮点数组分配到堆栈中。
浮点数占用4个字节(32位),因此大小为[1920 * 1080]的浮点数组将占用,1920 * 1080 * 4 = 8,294,000个字节。
堆栈中包含太多字节,因此我们得到堆栈溢出,程序崩溃。
但是,如果你这样做:
float* values = new float[1920 * 1080];
您正在将float数组分配到堆上,这称为动态数组。
堆比堆栈大得多,只受可用内存的限制,并且总能容纳8,294,000个字节。因此,你不会在这样做时发生堆栈溢出。
当你访问动态数组的一个元素时,它会从内存加载到堆栈中,它不需要加载所有元素,只需要加载你需要的元素,这样你就不会在访问数组元素时获得堆栈溢出。缺点是访问每个变量所花费的时间更长(仍然只有大约50到150纳秒),并且当使用{{1}不再需要数组时,需要显式释放分配给动态数组的内存运算符或者你会得到内存泄漏。