- 什么是堆叠和堆叠?
- 他们在电脑记忆中身处何方?
- 它们在多大程度上受到操作系统或语言运行时间的控制?
- 其范围是什么?
- 是什么决定了它们的大小?
- 是什么让一个更快?
当前回答
堆叠是作为执行线索的抓抓空间预留的内存。 当调用函数时, 在堆叠顶部保留一个区块, 用于本地变量和一些簿记数据。 当该函数返回时, 块会被未使用, 下次调用函数时可以使用。 堆叠总是保留在 LIFO 的顺序中( 最后一个在第一个出处) ; 最近保留的区块总是要解开的下一个区块 。 这样可以非常简单地跟踪堆叠; 从堆叠中释放一个区块只不过是调整一个指针而已 。
堆积是用于动态分配的内存。 与堆叠不同, 堆积区块的分配和分配没有强制模式; 您可以随时分配块块, 并随时释放它。 这就使得追踪堆积中哪些部分在任何特定时间分配或自由使用变得更加复杂; 许多定制的堆积分配器可以调和不同使用模式的堆积性能 。
每一串线索都有堆叠, 而通常应用程序只有一堆(尽管不同类型分配的多堆线索并不罕见) 。
直接回答你的问题:
它们在多大程度上受到操作系统或语言运行时间的控制?
当线索创建时, OS 会为每个系统级线索分配书架。 通常情况下, OS 会被语言运行时间调用来分配应用程序的堆积 。
其范围是什么?
堆栈附在线条上, 所以当线条退出时, 堆栈会被回收。 堆栈通常在运行时在应用程序启动时分配, 当应用程序( 技术处理) 退出时再回收 。
是什么决定了每个孩子的大小?
当创建线条时,会设定堆叠的大小。 程序启动时会设定堆积的大小, 但随着空间需要, 可能会增长( 分配器要求操作系统的内存更多 ) 。
是什么让一个更快?
堆叠速度更快, 因为访问模式使得从堆叠中分配和处理内存变得微不足道( 指针/ 内插器仅仅是递增或衰减) , 而堆叠在分配或交易地点的簿记上复杂得多 。 此外, 堆叠中的每个字节往往会非常频繁地被再利用, 这意味着它往往被映射到处理器的缓存处, 使其速度非常快 。 堆积的另一个性能冲击是, 堆积( 大多是一个全球资源) , 通常必须是多读的安全性, 也就是说, 每一个分配和交易地点需要 — 通常 — 与程序中的“ 所有” 其它堆积权限同步 。
明确表明:
图像来源 :vikashazrati.wordpress.com 译者注:
其他回答
(我将这一答案从另一个或多或少是这个问题的假象的问题移出。 )
您问题的答案是具体执行问题,可能因汇编者和处理结构而异。但这里是简单的解释。
- 堆叠和堆叠都是从基本操作系统分配的记忆区(通常是虚拟内存,按要求绘制成物理内存)。
- 在一个多轨环境中, 每条线将拥有自己的完全独立的堆叠, 但是它们会共享堆叠 。 同时访问必须控制在堆叠上, 无法在堆叠上 。
堆积物
- 堆积中包含一个链接的旧区块和空空区块列表。
new
或malloc
)通过在自由区块中创建一个合适的区块来满足。这需要更新堆积层上的区块清单。元数据信息堆积物层的区块 也常储存在堆积物层上 在一个小区域 就在每个块块的前面 - 随着堆积增加,新区块往往从下层地址分配到更高的地址。堆肥内存区块的大小随内存分配而增大。如果堆积太小,无法分配,则从基本操作系统获取更多的内存,其内存量往往会增加。
- 分配和分配许多小区块可能会让堆积物离开堆积物的状态下,在用过的区块之间有许许多多的小型自由区块。 分配大区块的请求可能会失败,因为没有一块自由区块能够满足分配要求,即使自由区块的组合体大小可能足够大。 这被称为“无自由区块 ” 。堆积碎裂.
- 当使用过的自由区块旁边的块块在交易时,新的自由区块可以与邻近的自由区块合并,以创建一个更大的自由区块,有效地减少堆积的碎裂。
堆叠
- 堆叠工作通常与一个名为CPU的特别登记簿密切配合进行。堆叠指针。最初,堆叠指针指向堆叠的顶部(堆叠上的最高地址)。
- CPU有特别指示推推堆叠和弹出弹出从堆放堆放的堆放物中推进保存堆叠指针当前位置的值,并减少堆叠指针。 A弹出检索堆叠指针指向的值,然后增加堆叠指针(不要被以下事实混淆):添加堆叠的值减少堆叠指针和删除删除a 值增加数保存并检索的值是 CPU 登记册的值。
- 如果函数有参数,则这些参数在调用到函数之前被推到堆栈上。然后,函数中的代码能够从当前的堆叠指针上导航堆栈以定位这些值。
- 当函数被命名为 CPU 时, 函数会使用特殊指令来按当前指示指示器后,当函数返回时,旧的指令指针会从堆叠中跳下来,然后在调用该函数后,在代码中恢复执行。
- 当输入一个函数时,会降低堆叠指针,以便在堆栈上为本地(自动)变量分配更多空间。如果函数有一个本地32位变量,则在堆栈上留出四个字节。当函数返回时,会将堆叠指针移回所分配的区域。
- 括号函数调用功能像一个护符一样工作。 每一个新调用功能参数、 返回地址和本地变量空间, 以及这些变量激活记录可以堆放嵌套电话,函数返回时会以正确的方式卸载。
- 由于堆叠是一个有限的内存块块, 您可以引起堆叠溢溢溢通过调用过多的嵌套函数和/ 或为本地变量分配过多的空间。 堆栈使用的记忆区域通常设置在堆栈底部( 最低地址) 下方的刻录将触发CPU的陷阱或例外。 此特殊条件随后会被运行时间捕获, 并转换成某种堆叠溢出例外 。
能否在堆叠上而不是堆叠上分配函数 ?
否,函数(即本地变量或自动变量)的激活记录被分配到堆叠上,不仅用于存储这些变量,还用于跟踪嵌套功能电话。
如何管理堆肥实际上要到运行时的环境。 C 使用malloc
C++ 和C++ 用途new
,但许多其他语言都有垃圾收集。
然而,堆叠是一个更低层次的特性,它与处理器结构紧密相连。 当没有足够的空间时堆积起来不会太难, 因为可以在处理堆积的图书馆电话中执行。 但是, 堆叠堆积起来往往是不可能的, 因为堆积溢出的时间太晚才被发现; 关闭行刑线是唯一可行的选择。
最重要的一点是,堆积和堆叠是记忆分配方法的通用术语,可以多种不同方式加以实施,这些术语适用于基本概念。
在一个堆叠的项目中,项目坐在另一堆的上方,按其放置的顺序排列,你只能删除顶端的项目(不折叠整件事情)。
堆叠的简单性在于您不需要保存包含分配内存每一部分的记录的表格; 您所需要的唯一状态信息是到堆栈尾端的单指针。 要分配和取消分配, 您只需递增和缩减该单指针。 注意: 有时可以安装堆叠, 以开始于内存的顶部, 向下延伸, 而不是向上增长 。
在堆积中,项目放置方式没有特定顺序。您可以按任何顺序接触和删除项目,因为没有明确的“顶部”项目。
高空分配需要完整记录什么是记忆分配,什么是记忆分配,什么不是,以及一些间接维护,以减少碎裂,发现毗连的内存部分大到足以满足要求的大小,等等。 内存可以在离开空闲空间的任何时候进行分配。 有时,内存分配器将执行维护任务,例如通过移动分配的内存或垃圾收集来消除内存的分散性,或者在运行时识别内存不再在范围之内的运行时间并进行分配。
这些图像应该能很好地描述 在堆叠和堆肥中分配和释放记忆的两种方式。
它们在多大程度上受到操作系统或语言运行时间的控制?
如前所述,堆叠和堆叠是一般术语,可以多种方式实施。呼叫堆叠存储与当前函数相关的信息, 如指向它从哪个函数调用, 以及任何本地变量。 因为函数调用其他函数, 然后返回, 堆叠会增长并缩放, 以便从调用堆栈往下更远的函数中保留信息。 一个程序实际上没有运行时间控制; 它由编程语言、 OS 甚至系统架构决定 。
堆积是一个通用术语,用于动态和随机分配的任何内存;即失序。内存通常由操作系统分配,应用程序中调用 API 函数来分配。管理动态分配内存需要相当一部分管理费,通常由所用编程语言或环境的运行时间代码处理。
其范围是什么?
调用堆栈是一个低层次的概念, 以至于它与编程意义上的“ 范围” 无关。 如果您将一些代码拆解, 您将会看到与堆叠部分相对的指针样式引用, 但就更高层次的语言而言, 语言会强制实施它自己的范围规则 。 但是, 堆栈的一个重要方面是, 一旦一个函数返回, 任何本地的函数都会立即从堆叠中解开。 这与您所编程语言是如何工作的有关。 在堆放过程中, 它也很难定义。 范围是由操作系统所暴露的, 但是您的编程语言可能会增加它关于“ 范围” 在您的应用程序中是什么的规则 。 处理器结构和 OS 使用虚拟地址, 处理器可以翻译为物理地址, 并且有页面错误等 。 它们会跟踪哪些页面属于哪个应用程序。 但是, 您从不需要担心这一点, 因为您只是使用你编程语言用于分配和自由记忆的方法, 并检查错误( 如果由于任何原因分配/ 解析失败 ) 。
是什么决定了每个孩子的大小?
同样,它取决于语言、编译器、操作系统和架构。 堆叠通常是预先分配的, 因为根据定义它必须是连续的内存。 语言编译器或操作系统决定其大小。 您不会在堆叠中存储大量数据, 因此它会足够大, 永远不能被充分利用, 除非在无谓的循环( 例如“ 堆叠溢出 ” ) 或其他不寻常的编程决定下。
对于任何可以动态分配的东西来说, 堆积是一个通用的术语。 取决于您看它的方式, 它的大小在不断变化。 在现代的处理器和操作系统中, 它的运作方式是非常抽象的, 所以通常你不需要担心它是如何在内心深处运作的, 除了( 在它允许你使用的语言中) 您不能使用你还没有分配到的记忆或者你已经释放的记忆。
是什么让一个更快?
堆叠速度更快, 因为所有自由内存总是毗连的 。 不需要保存自由内存所有部分的清单, 仅指堆叠当前顶部的单指针。 汇编者通常会将这个指针保存在特殊、 快速的文件中 。登记册登记簿更何况,堆叠上的后续操作通常集中在非常靠近的内存区内,这些内存区在非常低的水平上,对处理器置存的缓存器优化是有好处的。
其他人对大中风的反应也很好, 所以我要讲一些细节。
堆放和堆放不需要是单数的 。 堆放和堆放的多处常见情况是, 您在一个过程中拥有多个线条。 在此情况下, 每个线条都有自己的堆放。 您也可以有多个堆放。 例如, 某些 DLL 配置可能导致不同堆放的 DLL 分配不同的 DLL , 这就是为什么释放不同图书馆分配的内存通常是一个坏主意 。
在 C 中,您可以通过使用单花,它分配在堆叠上,而不是 Alloc,它分配在堆肥上。这个记忆不会保存在您的返回语句中,但它对刮痕缓冲很有用。
在 Windows 上做一个不使用很多内容的大型临时缓冲区不是免费的。 这是因为编译器将生成一个堆叠探测器循环, 每次输入您的函数时都会被调用, 以确保堆叠存在( 因为 Windows在堆叠的末尾使用一个单个的守护页面来检测堆叠的生长需要。 如果您访问堆叠尾端的多页内存, 您将会崩溃 ) 。 例如 :
void myfunction()
{
char big[10000000];
// Do something that only uses for first 1K of big 99% of the time.
}
CPU堆和堆肥与CPU和登记簿如何与记忆工作、机器组合语言如何运作、而不是高层次语言本身有实际联系,即使这些语言能决定小事。
所有现代CPU都与“相同”微处理理论合作: 它们都基于所谓的“ 注册者” 和一些“ 堆叠” 来取得性能。 所有 CPU 从一开始就有堆叠登记簿, 并且他们总是在这里, 正如我所知。 议会语言从一开始就是相同的, 尽管有各种变化... 直到微软及其中间语言(IL) 改变了范式, 有了OO虚拟机组装语言。 因此, 我们将来可以有一些 CLI/ CIL CPU (一个MS项目) 。
CPU有堆叠登记册来加速存取记忆,但与其他登记册相比,这些登记册有限,无法完全获取进程的所有可用内存。 这就是为什么我们谈论堆叠和堆积分配的原因。
简而言之,总的来说,堆积是慢慢的,用于“全球”实例和对象内容,因为堆叠的体积很小,速度很快,用于“本地”变量和参考(隐藏的指针要忘记管理它们)。
所以当我们用一种方法使用新关键字时, 引用( int) 是在堆叠中创建的, 但是对象及其所有内容( 价值类型以及对象) 都在堆积中创建, 如果我记得的话。 但是本地基本值类型和阵列是在堆叠中创建的 。
内存存存取的差别在于单元格参考级别:处理堆积,即整个过程的记忆,在处理CPU登记册方面要求比处理堆叠更为复杂,因为如果我记得,CPU堆叠登记册被用作基地址,因此,处理堆积存存存存取的差别就大于当地“更多”的堆叠。
这就是为什么当我们有非常长或无限的循环电话或循环时, 我们很快地被堆积物溢出, 而不冻结现代电脑上的系统...
C# Heap(ing) Vs Stack(ing) in.NET
https://en.wikipedia.org/wiki/Memory_management
https://en.wikipedia.org/wiki/Stack_register
大会语文资源:
堆栈基本上是一个容易获取的内存,仅将它的项目管理为-井-堆叠。事先知道大小的项目可以进入堆叠。数字、字符串、布林亚人的情况就是如此。
缩略堆积是您无法预先确定准确大小和结构的物品的内存。由于天体和阵列可以在运行时变异和变化,它们必须进入堆积。
资料来源:学员人数