繁体   English   中英

大数组大小的分段错误

[英]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> arraycppreference )。 如果您知道它会增长多大,您可以为 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::vectorstd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM