数组声明:全局与局部

Array declaration : Global Vs Local

为什么我们不能在 main 函数内或任何函数内局部地声明一个 10000000 个整数(或者说足够大)的数组,而它可以在全局范围内声明?

(编辑:全局变量通常不会进入堆)

这可能是由于可用 堆栈 内存和总内存之间的差异。局部变量放在堆栈上,而全局变量放在静态分配的内存部分。以下是一个更一般的问题,有一个很好的答案,概述了程序内存分配:

Global memory management in C++ in stack or heap?

tl;dr: space 对于局部变量是有限的。这就是 CPU 和操作系统的工作方式。


这是许多语言和实现共享的实现细节,例如典型桌面上的 C、C++ OS.

代码 运行 所在的大多数平台都预留了一些称为 堆栈 的内存,用于 return 地址和本地存储。这只是 CPU(Intel、AMD 等)如何执行机器代码的详细信息。

从堆栈分配非常快,但内存仅在函数调用 returns 之前有效。这使它成为 C/C++ 局部变量的理想选择。

但是,堆栈 space 是有限的,因此大量分配将失败并显示 堆栈溢出 - 即使还有足够的内存"elsewhere"。

程序启动时分配全局变量的内存。例如。可执行文件将指示 "I need so much space filled with zeroes, and I need so much space for data, and so much space for code."

"third"内存位置是Heap:用于malloc/new等分配的内存。堆比堆栈更昂贵(并且有更多问题需要处理),并且它们会一直存在直到您释放它们,这既好又负担。


一些旁注,因为它与问题没有直接关系,所以有意省略:

堆栈只是一个(连续的)内存范围,您只能从顶部分配和释放内存。这使得它具有局限性,方便快捷。

在现代桌面系统上,32 位进程通常不再 运行 内存不足,但地址不足 space:仍然有可用的物理内存,但所有可用的可能地址都在32 位字已用完。

每个执行线程都有自己的堆栈,而全局变量和堆在一个进程的所有线程之间共享。


为什么编译器不将大量分配移动到别处?

首先,"it has always been this way"。许多现有代码可能微妙地依赖于旧行为,并且 "improving" 编译器可能会破坏此代码。

其次,由于种种原因,唯一普遍适用的"elsewhere"就是堆。堆栈和堆分配之间的性能差异显着:

  • 堆分配更昂贵
  • 堆是共享的,因此必须同步从多个线程访问堆,这可能会非常昂贵。
  • 栈顶几乎总是在CPU的缓存中(因为该地址范围被访问得非常频繁)。堆更可能不是

大多数时候,这些细节并不重要,但对于某些操作,这种差异很重要。如果编译器决定在堆上进行一些分配,我们就会失去可预测性。