数组声明:全局与局部
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的缓存中(因为该地址范围被访问得非常频繁)。堆更可能不是
大多数时候,这些细节并不重要,但对于某些操作,这种差异很重要。如果编译器决定在堆上进行一些分配,我们就会失去可预测性。
为什么我们不能在 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的缓存中(因为该地址范围被访问得非常频繁)。堆更可能不是
大多数时候,这些细节并不重要,但对于某些操作,这种差异很重要。如果编译器决定在堆上进行一些分配,我们就会失去可预测性。