为啥大型静态数组会产生段错误而动态却不会? (C++)

Posted

技术标签:

【中文标题】为啥大型静态数组会产生段错误而动态却不会? (C++)【英文标题】:Why does a large static array give a seg-fault but dynamic doesn't? (C++)为什么大型静态数组会产生段错误而动态却不会? (C++) 【发布时间】:2013-04-29 01:11:10 【问题描述】:

以下代码给了我一个分段错误:

bool primeNums[100000000]; // index corresponds to number, t = prime, f = not prime

for (int i = 0; i < 100000000; ++i)

    primeNums[i] = false;

但是,如果我将数组声明更改为动态:

bool *primeNums = new bool[100000000];

我没有遇到段错误。我对这是为什么有一个大致的了解:在第一个示例中,内存被放在堆栈上,而在动态情况下,它被放在堆上。

你能详细解释一下吗?

【问题讨论】:

您已经指出了很大一部分原因。另一部分是,在典型情况下,堆栈大小相对有限——几兆字节左右。 【参考方案1】:
bool primeNums[100000000];

用完所有的stack 空间,因此,由于没有足够的堆栈空间来分配一个巨大的静态数组,所以会出现分段错误。

动态数组分配在heap上,因此,不容易出现分段错误。动态数组是在C++中使用new创建的,它会调用operator new分配内存,然后调用构造函数初始化分配的内存。

更多关于operator new如何工作的信息引用自以下标准[new.delete.single]:

要求的行为:

返回一个指向适当对齐存储的非空指针 (3.7.3),或者否则抛出 bad_alloc 异常。此要求对该函数的替换版本具有约束力。

默认行为:

——执行一个循环:在循环内,函数首先尝试分配请求的存储空间。未指定尝试是否涉及对标准 C 库函数 malloc 的调用。

— 如果尝试成功,则返回指向已分配存储的指针。否则,如果 set_new_handler() 的最后一个参数是空指针,则抛出 bad_alloc。

——否则,函数调用当前的 new_handler (18.4.2.2)。如果被调用的函数返回,则循环重复。

— 当尝试分配请求的存储空间成功或调用的 new_handler 函数没有返回时,循环终止。

所以使用带有new的动态数组,当空间不足时,默认会抛出bad_alloc,在这种情况下,你会看到一个异常而不是分段错误,当你的数组很大时,它最好使用动态数组或向量等标准容器。

【讨论】:

“堆”(基本上)是盒子中的所有空闲 RAM。 “堆栈”只是系统留出的一小部分,用于保存正在进行的函数调用列表和每个函数的几个局部变量。当你调用一个函数时,你调用的地方和你的局部变量被添加到堆栈上的列表中。当一个函数返回其局部变量并且从列表中删除调用位置时(返回后)。系统期望程序进行一百万个嵌套函数调用或具有一百万个局部变量或它们的某种组合是不合理的。 @John 感谢您的精彩解释。 静态数组不在堆栈上分配,除非 OP 有其他含义 static【参考方案2】:
bool primeNums[100000000];

此声明在stack space 中分配内存。堆栈空间是应用程序启动时分配的内存块。它通常在几千字节或几兆字节的范围内(取决于语言实现、编译器、操作系统和其他因素)。

此空间用于存储局部变量和静态变量,因此您必须小心谨慎,不要过度使用它。因为这是一个堆栈,所以所有分配都是连续的(分配之间没有空白)。

bool *primeNums = new bool[100000000];

在这种情况下,分配的内存是堆。这是可以分配大量新内存的空闲空间。

【讨论】:

【参考方案3】:

某些编译器或操作系统会限制堆栈的大小。在 Windows 上,默认值为 1 MB,但可以更改。

【讨论】:

【参考方案4】:

在第一种情况下,您在堆栈上分配内存:

bool primeNums[100000000]; // put 100000000 bools on stack

for (int i = 0; i < 100000000; ++i)

    primeNums[i] = false;

但是这是堆上的分配:

bool *primeNums = new bool[100000000]; // put 100000000 bools in the heap

由于堆栈(非常)有限,这就是段错误的原因

【讨论】:

以上是关于为啥大型静态数组会产生段错误而动态却不会? (C++)的主要内容,如果未能解决你的问题,请参考以下文章

为啥程序退出时全局或静态对象会导致崩溃?

静态数组仅在类定义内溢出堆栈(段错误 11),否则不会......?

错误动态数组

为啥 `python -c 'print('howdy')'` 会产生错误(在 zsh 中),但 `python -c 'print("howdy")'` 不会?

C里面静态动态,生命周期.作用域怎么区分?怎么用

cgo之调用静态库