我在堆栈与堆上有几个问题。
要知道的基本事情是堆栈比堆快,但是有限。 (如果我错了,请纠正我。)
但是,我总是想知道堆栈和堆是如何工作的。 RAM只是一块内存,它不分为'堆栈'和'堆'(或者是它?)。如果是这样,为什么我们首先在堆栈和堆中分割内存?
操作系统可以让我们能够在堆栈上分配所有内容 - >一切都变得更快 - >快乐的世界?
我很确定事实并非如此。但为什么!?谁能给我一个深入的答案呢?
很抱歉,如果这篇帖子是某人发过的一些帖子的副本,那么有很多与堆栈和堆相关的帖子,我找不到我的确切问题。如果您碰巧知道一个,请继续链接。
答案 0 :(得分:32)
堆栈:堆栈用作一种临时暂存区,供当前正在执行的代码块使用,以及任何称为当前块的块,以及任何称为该块的块,以及等等。当前块退出时,它所使用的局部变量将被遗忘。如名称所示,堆栈以后进先出的方式使用。
堆栈最重要的用途之一是跟踪当前的调用链。当一个函数调用另一个函数时,调用者将下一条指令的地址(返回地址)压入堆栈。当每个函数退出时,它会将调用者的返回地址从堆栈中弹出,并继续执行从该地址开始的代码。它还用于在调用者和被调用者之间传递函数参数和返回值。
堆:堆是不同的 - 它没有特定的顺序。如果要在代码块中分配内存并使该内存超出块的末尾,则在堆上分配它。当然,您还需要在某处存储指针/引用,以便其他代码可以找到该内存;大多数语言提供住宿。
速度:速度的差异不是由于内存本身的任何属性 - 正如您在问题中所说的,堆栈和堆通常都位于相同的物理内存中。由于堆栈的LIFO性质,在堆栈上分配空间很快:如果你把东西推到堆栈上,那么它只能有一个地方可以结束。相反,在堆上分配块需要在内存中找到足够大的连续空闲区域。堆栈分配可以像单个指令一样快;堆分配需要调用内存分配函数,如malloc()
。
静态与动态:在堆上分配内存是动态的 - 是否分配块,以及块的大小,可以根据程序在运行时接收的输入来确定。如果需要,甚至可以调整堆上分配的内存区域。它也可以可能在堆栈上动态分配内存(参见C标准库函数alloca()
),但是当前函数退出时该内存将丢失。堆栈分配通常是静态的 - 编译器确定(非寄存器)参数,返回数据和局部变量需要多少空间,并且在调用函数时生成代码以在堆栈上保留必要的空间。 / p>
示例:想象一下,您正在创建一个文字处理程序。您无法提前知道文档的大小,甚至不能同时使用多少文档。同时,只要用户想要保持打开状态,您就希望用户的文档保留在内存中。如果您尝试为堆栈中的文档分配内存,您将发现很难同时打开多个文档,并且您需要创建一个用于创建,编辑,保存和关闭文档的函数。在堆上分配空间允许您创建任意数量的文档,每个文档都适合其包含的数据,并避免将文档的生命周期与任何特定函数的生命周期联系起来。
摘要:简而言之,堆栈保存变量的值(有时使用寄存器),而堆用于分配将在当前块的生命周期之外使用的内存
答案 1 :(得分:9)
您不仅可以使用堆栈,因为堆栈需要后进先出分配&解除分配顺序(即,您只能释放最新分配的数据;在堆栈中,您无法释放一些旧数据并保留一些较新的数据。)
实际上,你可以摆脱堆栈(只保留堆)。请参阅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)上,堆栈指针是传统寄存器,而不是硬编码寄存器。
另见this&关于that的virtual address space个答案(以及其他答案)。
答案 2 :(得分:0)
两者的内存是相同的,但堆栈和堆是2种不同的数据结构,可用于不同的目的。
Stack是一种非常原始的抽象,任何微处理器都需要这些抽象来执行几个操作数(通常是处理器寄存器或存储器地址)上的指令。
堆是一个通用的分配内存区域,通常你想要存储未绑定到堆栈的数据,也就是说它们的生命周期更长,如果存储在堆栈中,或者换句话说,数据将是通过代码的不同部分进行访问。