谁负责C++中的栈和堆?
Who is responsible for the stack and heap in C++?
这不是他们的目的os是什么的问题。相反,问题是谁或什么负责发明堆栈和堆?
这些是C++编译器的发明吗?
os 是否指定了指定为 "stack" 和 "heap" 的 RAM 中的内存部分?
我很确定它们没有内置到硬件中,但我可能是错的。
此外,编译器是否负责生成汇编代码以指定哪些本地或函数数据将存储在堆栈上而不是 CPU 寄存器中?
Does the os specify memory sections in RAM designated "stack" and "heap"?
是的,对于每个程序,OS 为数据分配:
- 局部变量堆栈
- 静态数据的静态内存(全局变量或显式声明为静态的变量)
- 和一个用于动态内存管理的堆
I'm pretty sure they are not built into the hardware
硬件与内存布局无关。它提供内存,OS 完成剩下的工作。然而,在 x86/x64 和许多其他 CPU 架构上,例如,虽然 CPU 仍然没有强加堆栈,但它提供了专门的注册表和指令来管理堆栈,只有堆栈,因为它是一个非常重要的功能。
Also, does the compiler generate assembly code that specifies what information will be stored on the stack vs what maybe stored on a CPU's registers?
这些信息是由链接器而不是编译器产生的,它们存储在可执行文件头中,而不是汇编代码中。
编辑:事实上我已经用 'Does the os specify memory sections in RAM designated "stack" and "heap"?' 回答了这个问题。但我读过 "where" 而不是 "what"。抱歉。
这是实现定义的(C/C++ 不知道任何硬件)
这个 post 大约是 x86 上的 32 位 Linux。我不知道其他 architectures/OSes.
Are these inventions of the C++ compiler? Does the [OS] specify memory
sections in RAM designated "stack" and "heap"?
堆或自由存储
一个程序 different sections, one of them the .data
section. Dynamic memory allocation is usually implemented using the brk
system call (sbrk
builds on top of it). man brk
表示如下:
brk()
and sbrk()
change the location of the program break,
which defines the end of the process's data segment (i.e., the
program break is the first location after the end of the
uninitialized data segment). Increasing the program break has
the effect of allocating memory to the process; decreasing the
break deallocates memory.
这意味着 "heap" 或 "free store" 实际上是 .data
部分。
正如@kfx 在此答案的评论中所说,没有标准规定必须使用 brk
来实现 malloc
。使用 mmap
的实现也是可能的。
来自 man mmap
:
mmap()
函数应在地址 space 之间建立映射
一个进程和一个内存对象。
这基本上意味着一个文件(Unix意识形态:"everything is a file")被映射到内存中。
堆栈
栈也在.data
段,向下增长。从技术上讲,x86 允许您定义 downward-growing 堆栈段,但 Linux 不使用此功能。不知道为什么。
I'm pretty sure they are not built into the hardware but I could be
wrong.
不,他们不是。段在 OS 运行时设置,不存储在硬件中。
以下来自Linux4.2.
当MBR已经跳转到bootloader,bootloader执行完毕,执行这个(路径为/arch/x86/boot/header.S
):
# Normalize the start address
ljmp $BOOTSEG, $start2
start2:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
xorw %sp, %sp
这里所有的段寄存器都初始化为$BOOTSEG
,也就是0x7c0
。 sp
设置为 0x00
。否 esp
因为我们仍处于实模式!
初始化工作完成后,执行跳转到真正的内核。段寄存器设置如下:
movw $__BOOT_DS, %cx
movw $__BOOT_TSS, %di
movl %cr0, %edx
orb $X86_CR0_PE, %dl # Protected mode
movl %edx, %cr0
# Transition to 32-bit mode
.byte 0x66, 0xea # ljmpl opcode
2: .long in_pm32 # offset
.word __BOOT_CS # segment
ENDPROC(protected_mode_jump)
.code32
.section ".text32","ax"
GLOBAL(in_pm32)
# Set up data segments for flat 32-bit mode
movl %ecx, %ds
movl %ecx, %es
movl %ecx, %fs
movl %ecx, %gs
movl %ecx, %ss
段寄存器再次设置为cs
的内容。
Also, is the compiler responsible for generating assembly code that
specify which local or function data will be stored on the stack vs
CPU registers?
是的。对于函数调用,有不同的 calling conventions:一些将参数压入堆栈,一些将参数移入寄存器。
局部变量既可以用寄存器实现,也可以用栈实现。
未优化的 C 编译器将参数压入堆栈,调用函数,然后将它们弹出("stdcall" 调用约定)。
他们将堆栈用于局部变量,并结合 ebp
寄存器。
正如@chux 提到的,您可以编写在 'bare metal' 上运行的 C 或 C++ 代码,根本不需要任何操作系统。查看其工作原理可能有助于理解堆栈和堆的责任所在。
堆最容易解释。每次您 new
或 delete
对象(或调用 malloc/free
)时,编译器都会生成调用 allocation/deallocation 函数的代码。 (通常,new
通常会调用 malloc
)。所以编译器的职责只是生成对这两个函数的调用。
为堆分配的初始 space 由程序运行时的 OS 确定,或者(在裸机代码中)由将其指定为链接器设置的一部分的程序员确定.
那么这些功能在哪里,它们有什么作用?通常它们是与编译代码链接的运行时库的一部分(它们通常是用 C 或 C++ 编写的)。在 'bare metal' 系统上,它们直接管理堆 - 就 CPU 而言,这只是一个内存区域。 CPUs 没有任何堆的概念。如果涉及操作系统,这些函数通常只是调用 OS 提供的堆管理函数。有时,它是混合的,因为库可能会管理它自己的堆,但如果它用完,可能会调用 OS 以获取更多内存块。
堆栈不同。几乎每个 CPU 在硬件中都有堆栈的概念(尽管堆栈只存在于普通内存中)。当您调用函数并分配 stack-based 变量时,编译器会相应地生成代码来操作 'stack pointer'(一个特殊的 CPU 寄存器)。使用 multi-threaded 代码,每个线程都有自己的堆栈,OS 的 multi-tasking 内核负责为每个任务切换到适当的堆栈。
只是为了让您更加困惑,在 multi-threaded 系统中,每个线程的堆栈 space 通常是从堆中分配的。
Who or what is responsible for the invention of the stack and heap?
至于发明栈和堆,你最好在网上搜索一下。这些概念已经存在了几十年。
Are these inventions of the C++ compiler?
也许发明在这里是错误的术语。它们是数据结构。编译器和 OS(如果存在)负责组织和利用内存。
Does the os specify memory sections in RAM designated "stack" and "heap"?
这是 OS 特定的,可能因 OS 而异。有些 OSes 保留堆栈和堆区域,有些则不保留。
在我工作的嵌入式系统中,有两个堆区域:1)链接器中指定的区域,2)分配给OS的一部分内存。这两个区域都设置为零大小,因此我们没有任何堆。
堆栈区域由在 C 语言 Run-Time 库初始化之前运行的初始化代码设置。 RTL 代码也可以创建一些堆栈区域。我们的 RTOS 还创建堆栈区域(每个任务一个)。
所以,没有一个区域叫做堆栈。某些平台根本不使用堆栈概念(尤其是那些内存容量受到严格限制的平台)。
I'm pretty sure they are not built into the hardware but I could be wrong.
取决于硬件。简单廉价的硬件只分配一块 RAM(read/write 内存)。更复杂和昂贵的硬件可能会为堆栈、堆、可执行文件和数据分配单独的区域。常量可以放入 ROM(read-only 内存,例如 Flash)。没有支持一切的one-size或one-configuration。台式计算机与小型嵌入式系统 动物 不同。
Also, is the compiler responsible for generating assembly code that specify which local or function data will be stored on the stack vs CPU registers?
任务可以在链接器或编译器或两者中。
许多编译器 tool-chains 同时使用堆栈和 CPU 寄存器。许多变量和数据可以在堆栈、寄存器、RAM 或 ROM 中。编译器旨在充分利用平台资源,包括内存和寄存器。
一个很好的学习示例是编译器生成的汇编语言。还要查看链接器指令文件。寄存器或堆栈内存的使用非常依赖于数据结构(和类型),因此对于不同的功能可能有所不同。另一个因素是可用的内存量和种类。如果处理器可用的寄存器很少,编译器可能会使用堆栈传递变量。较大的数据(不适合寄存器)可以在堆栈上传递或传递给数据的指针。可用的选项和组合太多,无法在此一一列举。
总结
为了使 C 和 C++ 语言具有很好的可移植性,许多概念都委托给了实现(编译器/工具链)。其中两个概念通常称为 stack 和 heap。 C 和 C++ 语言标准使用一个简单的模型作为语言的环境。此外,还有 "hosted" 和 "semihosted" 等术语表示平台对语言要求的支持程度。 堆栈和堆是平台不需要支持语言的数据结构。它们确实有助于提高实施效率。
如果支持堆栈和堆,则它们的位置和管理是实现(工具链)的责任。编译器可以自由使用它自己的内存管理函数或 OS(如果存在)。堆栈和堆的管理可能需要硬件支持(例如虚拟内存管理或分页;以及栅栏)。堆栈不需要向堆增长。不需要堆栈向正方向增长。这些都取决于实现(工具链),他们可以随心所欲地实现和定位堆栈。 注意:它们很可能不会将变量放入 read-only 内存中,也不会在内存容量之外定位堆栈。
你错了。堆栈和堆并非起源于 C 或 C++。它们起源于早期机器的物理内存架构。
我将给出 x86 硬件的粗略故事(我敢肯定有很多我遗漏的细节,掩饰等)。我了解到其他硬件系列也有类似的演变,但我不太熟悉这些。
早期的 PC 有 640K 或更少的总内存,其中可以加载程序(从容量为几百 K 的软盘驱动器)并执行。这个内存区域后来被称为"conventional memory"。在开发早期 PC 时,人们认为这种内存量可能比以往任何时候都需要的多。
在当时,这是一个重要的进步,物理内存从 640K 增加到 1MB,使用扩展卡。有许多不兼容的变体。使用最广泛的是基于由微软、英特尔和其他几家公司联合开发的扩展内存规范。这被命名为扩展内存。
然后是 286 CPU,它支持保护模式,并且能够寻址超过 1MB 的内存 - 高达 64MB。额外的物理内存组(物理上独立的芯片组)用于安装额外的内存。在最初的实现中,这种内存比传统内存慢,但数量更多时更便宜。它被称为各种名称,例如扩展内存(XMS 规范)或高端内存(以访问它的设备驱动程序之一的名称命名)。 XMS 规范的更高版本允许寻址高达 4GB 的内存(即 32 位内存)。
程序需要常规内存和扩展内存 运行 - 如果没有足够的可用内存来加载可执行代码,程序就无法执行。这被称为堆栈 - 只是传统内存、扩展内存和由其他(non-Intel、non-Microsoft)供应商的驱动程序管理的类似类型内存的统称。它也由使用 LIFO 堆栈方法的程序管理(例如,当调用函数时,将上下文放置在堆栈数据结构上,并在函数返回时弹出)。在像 C 这样的语言中,局部变量和全局变量分配在 "stack" 上。由于可用量很小(在任何系统上都为 1MB 或更少),此内存总是非常宝贵。
扩展内存最初用于程序存储数据的额外内存需求。正如我上面所说,这种内存最初在物理上较慢,但数量更多时更便宜。它是在各种设备驱动程序(himem.sys 等)的帮助下进行管理的,其中每个设备驱动程序都提供了不同且不兼容的 API。堆最初是所有这些额外内存的统称,不管使用什么设备驱动程序来管理它。 Languages/libraries 当时支持动态内存分配(使用 C、malloc()
、free()
等)通常使用扩展内存(如果该内存在物理上不可用,则有一些回退)和处理与一系列可能的设备驱动程序通信的细节。一些支持带有指针(或类似构造)的语言的编译器使用不同的指针类型来引用堆栈或堆(near
和 far
指针,分别在早期版本的 XMS 和更高版本的 XMS [最多可寻址 4GB] huge
个指针)。
随着时间的推移,随着硬件技术的发展,物理内存类型之间的区别消失了 - 所有内存(CPU 缓存等除外)在物理上都是同一类型的内存,在给定的机器上(或芯片组调解并提供统一的内存接口,即使存在不同内存的物理组)。操作系统(unix、32 位 windows 等)出于管理进程的目的,倾向于保留类似于堆栈的内存部分(执行程序所需的基本内存)并使用配额对其进行限制.在现代操作系统中,这通常被称为堆栈,但是(由于虚拟内存管理等技术的奇迹)被分配给进程而不是在 system-wide 基础上,堆指的是其他可用内存到程序可以动态分配的进程。
这不是他们的目的os是什么的问题。相反,问题是谁或什么负责发明堆栈和堆?
这些是C++编译器的发明吗?
os 是否指定了指定为 "stack" 和 "heap" 的 RAM 中的内存部分?
我很确定它们没有内置到硬件中,但我可能是错的。
此外,编译器是否负责生成汇编代码以指定哪些本地或函数数据将存储在堆栈上而不是 CPU 寄存器中?
Does the os specify memory sections in RAM designated "stack" and "heap"?
是的,对于每个程序,OS 为数据分配:
- 局部变量堆栈
- 静态数据的静态内存(全局变量或显式声明为静态的变量)
- 和一个用于动态内存管理的堆
I'm pretty sure they are not built into the hardware
硬件与内存布局无关。它提供内存,OS 完成剩下的工作。然而,在 x86/x64 和许多其他 CPU 架构上,例如,虽然 CPU 仍然没有强加堆栈,但它提供了专门的注册表和指令来管理堆栈,只有堆栈,因为它是一个非常重要的功能。
Also, does the compiler generate assembly code that specifies what information will be stored on the stack vs what maybe stored on a CPU's registers?
这些信息是由链接器而不是编译器产生的,它们存储在可执行文件头中,而不是汇编代码中。
编辑:事实上我已经用 'Does the os specify memory sections in RAM designated "stack" and "heap"?' 回答了这个问题。但我读过 "where" 而不是 "what"。抱歉。
这是实现定义的(C/C++ 不知道任何硬件)
这个 post 大约是 x86 上的 32 位 Linux。我不知道其他 architectures/OSes.
Are these inventions of the C++ compiler? Does the [OS] specify memory sections in RAM designated "stack" and "heap"?
堆或自由存储
一个程序 different sections, one of them the .data
section. Dynamic memory allocation is usually implemented using the brk
system call (sbrk
builds on top of it). man brk
表示如下:
brk()
andsbrk()
change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.
这意味着 "heap" 或 "free store" 实际上是 .data
部分。
正如@kfx 在此答案的评论中所说,没有标准规定必须使用 brk
来实现 malloc
。使用 mmap
的实现也是可能的。
来自 man mmap
:
mmap()
函数应在地址 space 之间建立映射
一个进程和一个内存对象。
这基本上意味着一个文件(Unix意识形态:"everything is a file")被映射到内存中。
堆栈
栈也在.data
段,向下增长。从技术上讲,x86 允许您定义 downward-growing 堆栈段,但 Linux 不使用此功能。不知道为什么。
I'm pretty sure they are not built into the hardware but I could be wrong.
不,他们不是。段在 OS 运行时设置,不存储在硬件中。
以下来自Linux4.2.
当MBR已经跳转到bootloader,bootloader执行完毕,执行这个(路径为/arch/x86/boot/header.S
):
# Normalize the start address
ljmp $BOOTSEG, $start2
start2:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
xorw %sp, %sp
这里所有的段寄存器都初始化为$BOOTSEG
,也就是0x7c0
。 sp
设置为 0x00
。否 esp
因为我们仍处于实模式!
初始化工作完成后,执行跳转到真正的内核。段寄存器设置如下:
movw $__BOOT_DS, %cx
movw $__BOOT_TSS, %di
movl %cr0, %edx
orb $X86_CR0_PE, %dl # Protected mode
movl %edx, %cr0
# Transition to 32-bit mode
.byte 0x66, 0xea # ljmpl opcode
2: .long in_pm32 # offset
.word __BOOT_CS # segment
ENDPROC(protected_mode_jump)
.code32
.section ".text32","ax"
GLOBAL(in_pm32)
# Set up data segments for flat 32-bit mode
movl %ecx, %ds
movl %ecx, %es
movl %ecx, %fs
movl %ecx, %gs
movl %ecx, %ss
段寄存器再次设置为cs
的内容。
Also, is the compiler responsible for generating assembly code that specify which local or function data will be stored on the stack vs CPU registers?
是的。对于函数调用,有不同的 calling conventions:一些将参数压入堆栈,一些将参数移入寄存器。
局部变量既可以用寄存器实现,也可以用栈实现。
未优化的 C 编译器将参数压入堆栈,调用函数,然后将它们弹出("stdcall" 调用约定)。
他们将堆栈用于局部变量,并结合 ebp
寄存器。
正如@chux 提到的,您可以编写在 'bare metal' 上运行的 C 或 C++ 代码,根本不需要任何操作系统。查看其工作原理可能有助于理解堆栈和堆的责任所在。
堆最容易解释。每次您 new
或 delete
对象(或调用 malloc/free
)时,编译器都会生成调用 allocation/deallocation 函数的代码。 (通常,new
通常会调用 malloc
)。所以编译器的职责只是生成对这两个函数的调用。
为堆分配的初始 space 由程序运行时的 OS 确定,或者(在裸机代码中)由将其指定为链接器设置的一部分的程序员确定.
那么这些功能在哪里,它们有什么作用?通常它们是与编译代码链接的运行时库的一部分(它们通常是用 C 或 C++ 编写的)。在 'bare metal' 系统上,它们直接管理堆 - 就 CPU 而言,这只是一个内存区域。 CPUs 没有任何堆的概念。如果涉及操作系统,这些函数通常只是调用 OS 提供的堆管理函数。有时,它是混合的,因为库可能会管理它自己的堆,但如果它用完,可能会调用 OS 以获取更多内存块。
堆栈不同。几乎每个 CPU 在硬件中都有堆栈的概念(尽管堆栈只存在于普通内存中)。当您调用函数并分配 stack-based 变量时,编译器会相应地生成代码来操作 'stack pointer'(一个特殊的 CPU 寄存器)。使用 multi-threaded 代码,每个线程都有自己的堆栈,OS 的 multi-tasking 内核负责为每个任务切换到适当的堆栈。
只是为了让您更加困惑,在 multi-threaded 系统中,每个线程的堆栈 space 通常是从堆中分配的。
Who or what is responsible for the invention of the stack and heap?
至于发明栈和堆,你最好在网上搜索一下。这些概念已经存在了几十年。
Are these inventions of the C++ compiler?
也许发明在这里是错误的术语。它们是数据结构。编译器和 OS(如果存在)负责组织和利用内存。
Does the os specify memory sections in RAM designated "stack" and "heap"?
这是 OS 特定的,可能因 OS 而异。有些 OSes 保留堆栈和堆区域,有些则不保留。
在我工作的嵌入式系统中,有两个堆区域:1)链接器中指定的区域,2)分配给OS的一部分内存。这两个区域都设置为零大小,因此我们没有任何堆。
堆栈区域由在 C 语言 Run-Time 库初始化之前运行的初始化代码设置。 RTL 代码也可以创建一些堆栈区域。我们的 RTOS 还创建堆栈区域(每个任务一个)。
所以,没有一个区域叫做堆栈。某些平台根本不使用堆栈概念(尤其是那些内存容量受到严格限制的平台)。
I'm pretty sure they are not built into the hardware but I could be wrong.
取决于硬件。简单廉价的硬件只分配一块 RAM(read/write 内存)。更复杂和昂贵的硬件可能会为堆栈、堆、可执行文件和数据分配单独的区域。常量可以放入 ROM(read-only 内存,例如 Flash)。没有支持一切的one-size或one-configuration。台式计算机与小型嵌入式系统 动物 不同。
Also, is the compiler responsible for generating assembly code that specify which local or function data will be stored on the stack vs CPU registers?
任务可以在链接器或编译器或两者中。
许多编译器 tool-chains 同时使用堆栈和 CPU 寄存器。许多变量和数据可以在堆栈、寄存器、RAM 或 ROM 中。编译器旨在充分利用平台资源,包括内存和寄存器。
一个很好的学习示例是编译器生成的汇编语言。还要查看链接器指令文件。寄存器或堆栈内存的使用非常依赖于数据结构(和类型),因此对于不同的功能可能有所不同。另一个因素是可用的内存量和种类。如果处理器可用的寄存器很少,编译器可能会使用堆栈传递变量。较大的数据(不适合寄存器)可以在堆栈上传递或传递给数据的指针。可用的选项和组合太多,无法在此一一列举。
总结
为了使 C 和 C++ 语言具有很好的可移植性,许多概念都委托给了实现(编译器/工具链)。其中两个概念通常称为 stack 和 heap。 C 和 C++ 语言标准使用一个简单的模型作为语言的环境。此外,还有 "hosted" 和 "semihosted" 等术语表示平台对语言要求的支持程度。 堆栈和堆是平台不需要支持语言的数据结构。它们确实有助于提高实施效率。
如果支持堆栈和堆,则它们的位置和管理是实现(工具链)的责任。编译器可以自由使用它自己的内存管理函数或 OS(如果存在)。堆栈和堆的管理可能需要硬件支持(例如虚拟内存管理或分页;以及栅栏)。堆栈不需要向堆增长。不需要堆栈向正方向增长。这些都取决于实现(工具链),他们可以随心所欲地实现和定位堆栈。 注意:它们很可能不会将变量放入 read-only 内存中,也不会在内存容量之外定位堆栈。
你错了。堆栈和堆并非起源于 C 或 C++。它们起源于早期机器的物理内存架构。
我将给出 x86 硬件的粗略故事(我敢肯定有很多我遗漏的细节,掩饰等)。我了解到其他硬件系列也有类似的演变,但我不太熟悉这些。
早期的 PC 有 640K 或更少的总内存,其中可以加载程序(从容量为几百 K 的软盘驱动器)并执行。这个内存区域后来被称为"conventional memory"。在开发早期 PC 时,人们认为这种内存量可能比以往任何时候都需要的多。
在当时,这是一个重要的进步,物理内存从 640K 增加到 1MB,使用扩展卡。有许多不兼容的变体。使用最广泛的是基于由微软、英特尔和其他几家公司联合开发的扩展内存规范。这被命名为扩展内存。
然后是 286 CPU,它支持保护模式,并且能够寻址超过 1MB 的内存 - 高达 64MB。额外的物理内存组(物理上独立的芯片组)用于安装额外的内存。在最初的实现中,这种内存比传统内存慢,但数量更多时更便宜。它被称为各种名称,例如扩展内存(XMS 规范)或高端内存(以访问它的设备驱动程序之一的名称命名)。 XMS 规范的更高版本允许寻址高达 4GB 的内存(即 32 位内存)。
程序需要常规内存和扩展内存 运行 - 如果没有足够的可用内存来加载可执行代码,程序就无法执行。这被称为堆栈 - 只是传统内存、扩展内存和由其他(non-Intel、non-Microsoft)供应商的驱动程序管理的类似类型内存的统称。它也由使用 LIFO 堆栈方法的程序管理(例如,当调用函数时,将上下文放置在堆栈数据结构上,并在函数返回时弹出)。在像 C 这样的语言中,局部变量和全局变量分配在 "stack" 上。由于可用量很小(在任何系统上都为 1MB 或更少),此内存总是非常宝贵。
扩展内存最初用于程序存储数据的额外内存需求。正如我上面所说,这种内存最初在物理上较慢,但数量更多时更便宜。它是在各种设备驱动程序(himem.sys 等)的帮助下进行管理的,其中每个设备驱动程序都提供了不同且不兼容的 API。堆最初是所有这些额外内存的统称,不管使用什么设备驱动程序来管理它。 Languages/libraries 当时支持动态内存分配(使用 C、malloc()
、free()
等)通常使用扩展内存(如果该内存在物理上不可用,则有一些回退)和处理与一系列可能的设备驱动程序通信的细节。一些支持带有指针(或类似构造)的语言的编译器使用不同的指针类型来引用堆栈或堆(near
和 far
指针,分别在早期版本的 XMS 和更高版本的 XMS [最多可寻址 4GB] huge
个指针)。
随着时间的推移,随着硬件技术的发展,物理内存类型之间的区别消失了 - 所有内存(CPU 缓存等除外)在物理上都是同一类型的内存,在给定的机器上(或芯片组调解并提供统一的内存接口,即使存在不同内存的物理组)。操作系统(unix、32 位 windows 等)出于管理进程的目的,倾向于保留类似于堆栈的内存部分(执行程序所需的基本内存)并使用配额对其进行限制.在现代操作系统中,这通常被称为堆栈,但是(由于虚拟内存管理等技术的奇迹)被分配给进程而不是在 system-wide 基础上,堆指的是其他可用内存到程序可以动态分配的进程。