2011-11-17 123 views
25

可能重复:
What and where are the stack and heap为什么内存分成堆栈和堆?

我有一对夫妇的堆栈与堆问题。

要知道的基本知识是堆栈比堆快,但是有限。 (如我错了请纠正我)。

但是,我总是想知道堆栈和堆栈是如何工作的。 RAM只是一块内存,它不会被分成'堆栈'和'堆'(或者它是什么?)。如果是这样,为什么我们将堆栈中的内存和堆栈分开?

OS的可能只是让我们能在栈上分配的一切 - >一切进展快 - >幸福的世界?

我很确定情况并非如此。但为什么!?任何人都可以给我一个深入的答案吗?

很抱歉,如果这个职位是一些后有史以来的人提出的重复,有这么多相关的栈和堆,我无法找到确切的问题,我有。如果你碰巧知道一个,请继续并链接它。

+3

http://stackoverflow.com/questions/7123936/why-is-there-a-stack-and-a-heap – drdwilcox

+2

http://stackoverflow.com/questions/79923/what-and-where-are堆栈和堆 –

回答

6

你不仅可以使用堆栈,因为栈需要一个后进先出分配&释放顺序(即你只能取消分配最新的分配数据;在堆栈你不能解除分配一些旧的数据,并保持一定更新的)。

其实,你可以摆脱堆栈(只保留堆)。请参阅Appel的论文Garbage Collection Can Be Faster Than Stack Allocation和他的Compiling with Continuation书。

和堆不具有良好定义的含义(不是“动态分配的存储器,它是未在堆栈上”以外)。其实,在Linux系统中,分配的使用mmap系统调用内存中的很大一部分是相当快的(但malloc实现尽量避免mmap,宁愿重用free -d内存)。问题是分配小内存区域。

并阅读更多关于garbage collection techniques。在C或C++中,你可以使用Boehm's GC

堆栈通常很有用,尤其是递归函数调用。它非常有用(例如在C中)今天的处理器通常具有专用堆栈指针寄存器(由CALL & RET机器指令使用,用于呼叫&返回)。但情况并非总是如此;在一些处理器(例如IBM360)上,堆栈指针是一个传统的寄存器,而不是硬编码的。

+0

非常有用的信息,谢谢:) – xcrypt

0

存储器仅仅是两者的相同,但栈和堆是用于不同目的的两个不同的数据结构。

堆栈是受任何微处理器以一对夫妇操作数(通常是处理器的寄存器或存储器地址)的执行指令需要一个非常原始的抽象。

堆是一个通用分配内存区域,通常你想要存储没有绑定到堆栈的数据,也就是说,如果它们存储在堆栈中,它们的生存期会更长,或者换言之,数据将要通过代码的不同部分进行访问。

+0

那么,我可以只在主函数堆栈中分配一些对象,并在整个程序中使用它,我不需要堆。你的论点可能是堆栈有限,但我打算提出的问题之一是:为什么堆栈有限? (由于上述原因) – xcrypt

+0

堆栈受限制,因为它从内存空间地址的一个极端增长到另一个极端。如果它是无限的,那么当出现中断时(因为中断会将CPU状态保存在堆栈中),您可能会损坏堆中存储在堆中的日期,因此必须在某处设置人为限制以避免此情况(这是因为存在当达到该限制时,着名的“堆栈溢出”消息)。 –

23

堆栈:堆栈被用作临时暂存区,供当前正在执行的代码块以及任何称为当前块的块和任何称为该块的块等等使用。当前块存在时,它所使用的局部变量被遗忘。正如名称所示,堆栈以后进先出的方式使用。

该堆栈最重要的用途之一是跟踪当前的调用链。当一个函数调用另一个函数时,调用者将下一条指令的地址(返回地址)推入堆栈。当每个函数退出时,它会将其调用者的返回地址从堆栈中弹出,并继续执行从该地址开始的代码。它也用于在调用者和被调用者之间传递函数参数和返回值。

堆:堆是不同的 - 有没有特定的顺序。如果你想在一段代码中分配内存,并让该内存超出块的末尾,你可以将它分配到堆上。当然,您还需要在某处存储指针/引用,以便其他代码可以找到该内存;大多数语言提供住宿。

速度:速度的差异并不是由于内存本身的任何属性 - 正如你在你的问题中所说的那样,栈和堆通常都在相同的物理内存中。在堆栈中分配空间很快,原因在于堆栈的LIFO性质:如果将某些东西压入堆栈,只能有一个地方结束。相比之下,在堆上分配块需要在内存中找到足够大的连续空闲区域。堆栈分配可以像单条指令一样快;堆分配需要调用内存分配功能,如malloc()

静态与动态:在堆上分配内存是动态的 - 是否分配块和块的大小可以根据程序在运行时接收的输入来确定。在堆上分配的内存区域甚至可以根据需要调整大小。它也可能是也可以动态分配堆栈中的内存(请参阅C标准库函数alloca()),但是当前函数退出后该内存将立即丢失。堆栈分配通常是静态的 - 编译器确定(非注册)参数,返回数据和本地变量需要多少空间,并且在调用该函数时生成代码以在堆栈中保留必要的空间。

示例:想象一下,您正在创建一个文字处理器。您无法提前知道文档的大小,甚至可能同时使用多少个文​​档。与此同时,只要用户想让它们保持打开状态,就希望用户的文档保留在内存中。如果您尝试为堆栈中的文档分配内存,您会发现很难一次打开多个文档,并且您需要创建一个创建,编辑,保存和关闭文档的函数。在堆上分配空间允许您创建尽可能多的文档,每个文档都根据其包含的数据进行适当的大小设置,并避免将文档的生命周期与任何特定功能的生命周期挂钩。

总结:简而言之,堆栈保存变量的值(有时使用寄存器),而堆用于分配将在当前块的生命周期之外使用的内存。

+0

你能举个例子说明我被迫使用堆的一些观点吗?例如,我可以在父函数中为整个程序分配堆栈中的所有内容,并通过地址将所有内容传递给子函数。 编辑:为了这个问题,让我们忽略堆栈受限于RAM内存已满的其他内容。 – xcrypt

+0

@xcrypt这需要您事先知道您的程序可能执行的每个内存分配。或者,您可以在您的堆栈中分配一个巨大的块,以后可以动态分配内存。该块将是堆的功能等同物。我将在上面添加一个示例。 – Caleb

+0

您提到编译器会在运行前计算出它需要的堆栈空间量,对吗?递归的情况也适用吗?因为如果这是正确的,那么在编译代码之后编译器是否能够立即提示无限递归呢? – Dubby