我知道每个正在运行的进程在虚拟内存中都有与之关联的页面,并且很少有页面会根据需要加载到主内存中。我也知道该程序将有一个堆栈和一个堆来分配动态内存。这是我的问题。
- 堆栈也是主内存中某些页面的一部分吗?
- 当程序进入等待状态时会发生什么?堆栈指针、程序计数器和其他信息存储在哪里?
- 为什么栈会变小,而堆会变大?
- L1、L2 缓存可以只包含一块连续的内存,还是可以包含堆栈和堆的一部分?
你能推荐一本涵盖这些内容的好书吗?
我知道每个正在运行的进程在虚拟内存中都有与之关联的页面,并且很少有页面会根据需要加载到主内存中。我也知道该程序将有一个堆栈和一个堆来分配动态内存。这是我的问题。
你能推荐一本涵盖这些内容的好书吗?
堆栈也是主内存中某些页面的一部分吗?
是的 - 堆栈通常存储在内存的“低”地址中,并向上填充到其上限。堆通常存储在地址空间的“顶部”并朝着堆栈增长。
当程序进入等待状态时会发生什么?堆栈指针、程序计数器和其他信息存储在哪里?
O/S 为每个正在运行的进程存储一个“上下文”。保存和恢复进程状态的操作称为“上下文切换”。
为什么栈会变小,而堆会变大?
据我所知,只是一个约定。堆栈并没有真正“增长”它有固定的分配。
L1、L2 缓存可以只包含一块连续的内存,还是可以包含堆栈和堆的一部分?
缓存仅包含已使用(最近或附近)的部分 RAM 的快照。在任何时候,他们都可以从其中的地址空间的任何部分获得内存。显示在哪里很大程度上取决于缓存的结构参数(块长度、关联性、总大小等)。
我建议计算机体系结构:一种定量方法作为底层硬件的一个很好的参考,以及任何关于如何“管理”硬件的操作系统书籍。
这是我对这些问题的理解:
堆栈也是主内存中某些页面的一部分吗?
是的,堆栈通常也存储在进程地址空间中。
当程序进入等待状态时会发生什么,堆栈指针、程序计数器和其他信息存储在哪里?
当操作系统将进程从活动状态变为等待状态时,它会将所有寄存器(包括堆栈指针和程序计数器)存储在内核的进程表中。然后,当它再次激活时,操作系统会将所有这些信息复制回原处。
为什么栈会变小,而堆会变大?
那是因为它们通常必须共享相同的地址空间,并且为了方便起见,它们每个都从地址空间的一端开始。然后他们彼此相向而行,形成了长大后长大的行为。
L1,L2 缓存可以只包含一块连续内存还是可以包含堆栈和堆的某些部分?
CPU 缓存将存储最近使用的内存块。因为堆栈和堆都存储在主内存中,所以缓存可以包含两者的一部分。
3. 为什么栈向下增长,堆向上增长?
请注意,在某些系统(例如,某些 HP 系统)上,堆栈是向上增长而不是向下增长。而在其他系统(例如,IBM/390)上,根本没有真正的硬件堆栈,而是从用户空间内存动态分配的页面池。
通常,堆可以向任何方向增长,因为它可能包含许多分配和释放孔,因此最好将其视为松散的页面集合,而不是 LIFO 堆栈类型的结构。话虽如此,大多数堆实现都会在预定的地址范围内扩展其空间使用量,并根据需要对其进行扩展和收缩。
当使用保护模式操作系统(如 Windows 或 Linux)时,每个进程都有大量内存页面可供给定进程使用。如果需要更多内存,可以调入更多内存。
通常,该进程将分配给它的内存分成两部分。一个是堆,另一个是堆栈。堆栈的底部由 arm 上的堆栈指针 r13 和 x86 上的 esp 指定。当人们在堆栈上创建一个变量时,堆栈指针会移动以允许所需的额外空间。这是由汇编指令 PUSH 完成的。同样,当变量超出范围时,它会从堆栈中弹出。
通常,PUSH 会导致堆栈指针递减,使堆栈指针值上方的值“在堆栈上”。
内存的另一部分可用于堆。然后可以使用 malloc 或 new 进行分配。每个线程必须有自己的堆栈,但可以与进程中的其他线程共享堆。
当内核重新调度线程时,它会存储堆栈寄存器并将堆栈寄存器更改为新堆栈。是否可能需要或可能不需要存储程序计数器,具体取决于调度方式。
缓存与堆栈或堆无关。它由处理器管理,并提供了一种方法来确保 CPU 所需的数据就在手边,这样它就不必等待总线来获取它。完全由 CPU 来确保主内存中的内容与缓存中存储的内容相同。唯一真正需要担心缓存的是使用 DMA 时。必须手动刷新或同步缓存,以确保 CPU 不信任缓存并实际从主内存中获取数据。
你应该看看我教授的幻灯片,来自我的建筑课。第 6 单元。真的帮助我理解了,所有你问过的和其他人都回答过的,还有更多,如果你想要更深入的知识。