大型阵列的内存区段错误

下面的代码给了我一个在2GB 机器上运行,但在4GB 机器上运行的内存区段错误。

int main()
{
int c[1000000];
cout << "done\n";
return 0;
}

数组的大小只有4Mb。在 c + + 中,数组的大小是否有限制?

124336 次浏览

你可能只是堆栈溢出了。这个数组太大了,无法适应程序的堆栈区域; 对于大多数主流桌面/服务器操作系统上的用户空间代码,堆栈增长限制通常是8 MiB 或1 MiB。(普通的 C + + 实现使用 asm 栈进行自动存储,即非 static本地变量数组。这使得当函数返回或异常通过它们传播时,可以免费释放它们。)

如果动态分配数组,假设您的机器有足够的内存,那么应该没有问题。

int* array = new int[1000000];    // may throw std::bad_alloc

但是请记住,这将需要您手动 delete[]数组以避免内存泄漏,即使您的函数通过异常退出。在现代的 C + + 中,强烈反对手动的 new/delete,更喜欢 拉尔


更好的解决方案是使用 std::vector<int> array (首选)。你可以为1000000个元素预留空间,如果你知道它将增长多大。或者甚至使用 resize来默认构造它们(即零初始化内存,不同于声明一个没有初始化器的普通 C 样式数组) ,如 std::vector<int> array(1000000)

std::vector对象超出范围时,它的析构函数将为您释放存储,即使这是通过父函数捕获的子函数中的异常发生的。

在这种情况下,将在堆栈上分配数组,尝试使用 alloc 分配相同大小的数组。

在 C 或 C + + 中,本地对象通常是在堆栈上分配的。您在堆栈上分配了一个大型数组,超出了堆栈的处理能力,因此您将获得一个 堆栈溢出。

不要在堆栈上本地分配它,而是使用其他位置。这可以通过创建对象 全球性的或在全局 很多上分配它来实现。如果不使用来自任何其他编译单元的全局变量,则可以使用它。要确保这种情况不会偶然发生,请添加静态存储说明符,否则只需使用堆即可。

这将在 BSS 段中进行分配,BSS 段是堆的一部分。因为它是在静态存储中,所以如果不指定其他方式,它的初始化值为零,这与包括数组在内的本地变量(自动存储)不同。

static int c[1000000];
int main()
{
cout << "done\n";
return 0;
}

非零初始化器将使编译器在 DATA 段中进行分配,DATA 段也是堆的一部分。(数组初始值设定项的所有数据将在可执行文件中占用空间,包括所有隐式的尾随零,而不仅仅是 BSS 中的大小为0-init)

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

但是要小心,记忆是一种有限的资源,强大的力量会带来巨大的责任:)

普通数组是在堆栈中分配的,堆栈的容量限制为几兆字节,因此程序会出现堆栈溢出和崩溃。

也许最好的方法是使用堆分配的基于 矢量的数组,它可以增长到几乎整个内存的大小,而不是普通的数组。

上网试试!

#include <vector>
#include <iostream>


int main() {
std::vector<int> c(1000000);
std::cout << "done\n";
return 0;
}

然后您可以像通常一样访问数组的元素 c[i]和/或得到它的大小 c.size()(int元素的数量)。

如果你想要固定尺寸的多维数组,那么混合使用 矢量数组,如下所示:

上网试试!

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