关于内核:程序堆栈和堆,它们如何工作?

Program stack and heap, how do they work?

我知道每个正在运行的进程在虚拟内存中都有与之相关联的页面,并且很少有页面会根据需要加载到主内存中。我还知道程序将有一个堆栈,也有一个用于分配动态内存的堆。这是我的问题。

  • 堆栈也是主内存中某个页面的一部分吗?
  • 当程序移动到等待状态时会发生什么?堆栈指针、程序计数器和其他信息存储在哪里?
  • 为什么堆向下生长而堆向上生长?
  • 一级、二级缓存只能包含一个连续内存块,还是可以包含堆栈和堆的一部分?
  • 你能推荐一本涵盖这些内容的好书吗?


  • 是-堆栈通常存储在内存的"低"地址中,并向上填充到其上限。堆通常存储在地址空间的"顶部",并向堆栈增长。

  • O/S为每个正在运行的进程存储一个"上下文"。保存和恢复进程状态的操作称为"上下文切换"。

  • 只是一个惯例。堆栈并没有真正"增长",它有固定的分配。

  • 缓存只包含已使用的RAM部分(最近或附近)的快照。在任何时候,他们都可以从地址空间的任何部分获得内存。显示在哪里的内容很大程度上取决于缓存的结构参数(块长度、关联性、总大小等)。

  • 我建议使用计算机体系结构:一种定量方法,作为底层硬件的良好参考,以及任何有关操作系统的书籍,以了解如何"管理"硬件。


    这是我对这些问题的理解:

  • 堆栈也是主内存中某个页面的一部分吗?

    是的,堆栈通常也存储在进程地址空间中。

  • 当程序移动到等待状态,堆栈指针、程序计数器和其他信息存储在哪里时会发生什么?

    当操作系统将进程从活动状态变为等待状态时,它将所有寄存器(包括堆栈指针和程序计数器)存储在内核的进程表中。然后,当它再次激活时,操作系统会将所有信息复制回原来的位置。

  • 为什么堆向下生长而堆向上生长?

    因为它们通常必须共享相同的地址空间,为了方便起见,它们都从地址空间的一端开始。然后他们互相成长,给予成长下来的行为。

  • 一级、二级缓存只能包含一个连续内存块,还是可以包含堆栈和堆的某些部分?

    CPU缓存将存储最近使用的内存块。因为堆栈和堆都存储在主内存中,所以缓存可以包含这两者的一部分。


  • 三。为什么堆向下生长而堆向上生长?

    请注意,在某些系统(例如,某些HP系统)上,堆栈会向上而不是向下增长。在其他系统(如IBM/390)上,根本没有真正的硬件堆栈,而是从用户空间内存动态分配的页面池。

    通常,堆可以朝任何方向增长,因为它可能包含许多分配和释放漏洞,因此最好将其视为松散的页面集合,而不是后进先出(LIFO)堆栈类型结构。也就是说,大多数堆实现将其空间使用扩展到预定的地址范围内,并在必要时对其进行增长和收缩。


    你应该从我的建筑学课上看看我教授的幻灯片。第6单元。真的帮助我理解了,你问的和别人回答的,还有更多,如果你想要更深入的知识。


    当一个人使用一个保护模式的操作系统(如Windows或Linux)时,每个进程都有一大堆内存页可供给定的进程使用。如果需要更多内存,可以调入更多内存。

    通常,这个过程将给它的内存分为两部分。一个是堆,另一个是堆。堆栈底部由ARM上的堆栈指针R13和x86上的esp指定。当在堆栈上创建变量时,堆栈指针将被移动以允许所需的额外空间。这是由汇编程序指令推送完成的。同样,当变量超出范围时,它将从堆栈中弹出。

    通常,push会使堆栈指针递减,使值高于堆栈指针值"on the stack"。

    内存的另一部分可用于堆。然后可以使用malloc或new进行分配。每个线程必须有自己的堆栈,但可以与进程中的其他线程共享该堆栈。

    当内核重新调度线程时,它存储堆栈寄存器并将堆栈寄存器更改为新堆栈。如果可能或可能不需要存储程序计数器,则取决于进行调度的方式。

    缓存与堆栈或堆无关。它由处理器管理,并提供了一种方法来确保CPU所需的数据接近手头,这样它就不必等待总线来获取数据。这完全取决于CPU,以确保主内存中的内容与缓存中存储的内容相同。唯一一次真正需要担心的缓存是在使用DMA时。它必须手动刷新或同步缓存,以确保CPU不信任缓存,并实际从主内存中获取数据。