[英]Segmentation fault on large array sizes
以下代码在 2Gb 机器上运行时出现分段错误,但在 4GB 机器上运行。
int main()
{
int c[1000000];
cout << "done\n";
return 0;
}
数组的大小只有 4Mb。 c++ 中可以使用的数组大小是否有限制?
您可能只是在这里遇到堆栈溢出。 数组太大,无法放入程序的堆栈区域; 大多数主流桌面/服务器操作系统上的用户空间代码的堆栈增长限制通常为 8 MiB 或 1 MiB。 (普通的 C++ 实现使用 asm 堆栈进行自动存储,即非static
局部变量数组。这使得在函数返回或异常通过它们传播时可以免费地释放它们。)
如果你动态分配数组你应该没问题,假设你的机器有足够的内存。
int* array = new int[1000000]; // may throw std::bad_alloc
但请记住,这将需要您手动delete[]
数组以避免内存泄漏,即使您的函数通过异常退出。 在现代 C++ 中强烈反对手动 new/delete,更喜欢RAII 。
更好的解决方案是使用std::vector<int> array
( cppreference )。 如果您知道它会增长多大,您可以为 1000000 个元素保留空间。 甚至将其resize
为默认构造它们(即零初始化内存,与声明没有初始化器的普通 C 样式数组不同),例如std::vector<int> array(1000000)
当std::vector
对象超出范围时,它的析构函数将为您释放存储空间,即使这是通过父函数捕获的子函数中的异常发生的。
在 C 或 C++ 中,本地对象通常分配在堆栈上。 您在堆栈上分配了一个大数组,超出了堆栈可以处理的范围,因此您得到了stackoverflow。
不要在堆栈上本地分配它,而是使用其他地方。 这可以通过使对象成为全局对象或将其分配到全局堆上来实现。 如果您不使用来自任何其他编译单元的全局变量,则可以。 为确保这不会意外发生,请添加静态存储说明符,否则只需使用堆。
这将在作为堆的一部分的 BSS 段中分配。 由于它在静态存储中,因此如果您没有另外指定,它的初始化为零,这与包括数组在内的局部变量(自动存储)不同。
static int c[1000000];
int main()
{
cout << "done\n";
return 0;
}
非零初始化器将使编译器在 DATA 段中分配,这也是堆的一部分。 (并且数组初始值设定项的所有数据都将在可执行文件中占用空间,包括所有隐式尾随零,而不仅仅是 BSS 中零初始化的大小)
int c[1000000] = {1, 2, 3};
int main()
{
cout << "done\n";
return 0;
}
这将在堆中的某个未指定位置分配:
int main()
{
int* c = new int[1000000]; // size can be a variable, unlike with static storage
cout << "done\n";
delete[] c; // dynamic storage needs manual freeing
return 0;
}
此外,如果您在大多数 UNIX 和 Linux 系统中运行,您可以通过以下命令临时增加堆栈大小:
ulimit -s unlimited
但要小心,记忆是一种有限的资源,强大的力量伴随着巨大的责任:)
在这种情况下,您的数组正在堆栈上分配,尝试使用 alloc 分配相同大小的数组。
因为您将数组存储在堆栈中。 您应该将其存储在堆中。 请参阅此链接以了解堆和堆栈的概念。
您的普通数组在堆栈中分配,并且堆栈限制为几兆字节,因此您的程序会出现堆栈溢出并崩溃。
最好的方法可能是使用堆分配的基于std::vector的数组,它几乎可以增长到整个内存的大小,而不是你的普通数组。
#include <vector>
#include <iostream>
int main() {
std::vector<int> c(1000000);
std::cout << "done\n";
return 0;
}
然后你可以像往常一样访问数组的元素c[i]
和/或获取它的大小c.size()
( int
元素的数量)。
如果您想要具有固定维度的多维数组,请混合使用std::vector和std::array ,如下所示:
#include <vector>
#include <array>
#include <iostream>
int main() {
std::vector<std::array<std::array<int, 123>, 456>> c(100);
std::cout << "done\n";
return 0;
}
在上面的示例中,您得到的行为几乎与分配普通数组int c[100][456][123];
相同。 (除了向量在堆而不是堆栈上分配),您可以像在普通数组中一样访问元素c[10][20][30]
。 上面的这个示例还在堆上分配数组,这意味着您可以将数组大小增加到整个内存大小,而不受堆栈大小的限制。
要获取指向向量中第一个元素的指针,请使用&c[0]
或仅c.data()
。
可能还有另一种对我有用的方法! 您可以通过更改数组的数据类型来减小数组的大小:
int main()
{
short c[1000000];
cout << "done\n";
return 0;
}
或者
int main()
{
unsigned short c[1000000];
cout << "done\n";
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.