banner
NEWS LETTER

第八章:内存管理

Scroll down

操作系统第八章:内存管理 (Memory Management) 通关笔记

一、 内存管理基础:程序是怎么住进内存的?

你可以把内存想象成一家“大酒店”,程序是“客人”。客人必须先住进酒店,才能开始活动(被 CPU 执行)。

1. 基础硬件认知

  • 存储层次:CPU 只能直接访问主存(Main memory)和寄存器(Registers) 。

  • 速度差异:寄存器访问通常只需一个 CPU 时钟周期或更少,而主存可能需要多个周期 。为了解决速度差,在它们之间加入了缓存(Cache)

  • 地址空间

    • 逻辑地址(虚拟地址):由 CPU 生成的地址(客人的房卡上写的房间号) 。

    • 物理地址:内存单元看到的实际地址(酒店真实的物理房间号) 。

  • 内存管理单元 (MMU):它是前台接待员,负责将逻辑(虚拟)地址映射为物理地址的硬件设备 。用户程序永远只和逻辑地址打交道,看不到真实的物理地址 。

2. 地址绑定(Address Binding):房号是什么时候定下来的?

指令和数据绑定到具体的内存地址,可能发生在三个阶段 :

  • 编译时 (Compile time):如果你事先就知道程序要放在哪,就可以直接写死绝对地址。如果起始位置变了,必须重新编译代码 。

  • 加载时 (Load time):如果编译时不知道在哪,编译器会生成“可重定位代码”。具体位置等程序加载进内存时再定 。

  • 执行时 (Execution time):如果进程在运行期间还可能在内存里挪动,那就必须把绑定推迟到运行时。这需要硬件(如基址和界限寄存器)的支持 。

3. 内存空间优化技术(客房不够用怎么办?)

  • 动态加载 (Dynamic Loading):子程序直到被调用时才加载 。好处是未使用的例程绝不会被加载,能更好地利用内存空间 。

  • 动态链接 (Dynamic Linking):链接推迟到执行时进行 。使用一小段称为存根(stub)的代码来定位合适的内存驻留库例程 。这对系统库特别有用 。

  • 覆盖 (Overlays):内存中只保留任何给定时间所需的指令和数据 。通常在进程比分配给它的内存还要大时使用 。

  • 交换 (Swapping):进程可以暂时被换出(swapped out)到后备存储(Backing store),等需要时再换回(swapped in)内存继续执行 。后备存储是一个足够大且能提供直接访问的快速磁盘 。交换的主要时间开销是数据传输时间 。


二、 连续内存分配:一人独占一整块地

系统将内存分为两部分:操作系统住在低内存(带中断向量),用户进程住在高内存 。

1. 内存保护

  • 使用重定位寄存器 (Relocation register)界限寄存器 (Limit register)来保护用户进程不受彼此干扰,并保护操作系统 。

  • 逻辑地址必须小于界限寄存器,重定位寄存器包含最小物理地址的值 。

2. 动态存储分配(怎么分配空闲地块?)

当一个进程到来时,操作系统会从足够大的孔(Hole,可用的空闲内存块)中为它分配空间 。有三种分配策略:

  • First-fit (首次适应):分配第一个足够大的孔 。

  • Best-fit (最佳适应):分配足够大中的最小孔 。必须搜索整个列表,这会产生最小的剩余孔 。

  • Worst-fit (最坏适应):分配最大的孔 。产生最大的剩余孔 。

  • 注:在速度和存储利用率上,首次适应和最佳适应通常优于最坏适应 。

3. 内存碎片(Fragmentation)

  • 外部碎片 (External Fragmentation):总内存空间足够满足请求,但它们不连续,碎了一地 。可以通过紧凑 (Compaction)技术(洗牌合并空闲内存)来减少外部碎片,但这要求地址重定位是动态的且在执行时进行 。

  • 内部碎片 (Internal Fragmentation):分配给进程的内存可能略微大于请求的内存 。多出来的那一点就在分好的区域内部,没法给别人用 。


三、 分页机制 (Paging):“切蛋糕”式的系统管理

核心思想:分页允许进程的逻辑地址空间不连续 。就像把大蛋糕切成标准化的小块,哪里有空盘子就放哪。

1. 基本架构

  • 物理内存被划分为固定大小的块,称为帧 (frames)(大小一般在 512 字节到 8192 字节之间) 。

  • 逻辑内存被划分为相同大小的块,称为页 (pages)

  • 分页机制会产生内部碎片

2. 地址转换

CPU 生成的地址被切分为两部分 :

  • 页号 (p):作为页表的索引,页表里存着每一页对应的物理基址 。

  • 页偏移 (d):和基址结合,生成最终发给内存的物理地址 。

3. 硬件支持与 TLB

  • 页表保存在主存中 。页表基址寄存器 (PTBR) 指向页表,页表长度寄存器 (PRLR) 指示页表大小 。

  • TLB (翻译后备缓冲器):因为传统的页表机制访问一次数据需要两次内存访问(查一次表,取一次数据),所以引入了 TLB 这种快速查找硬件缓存(关联内存)来加速 。

  • 有效访问时间 (EAT) 计算

    • 设命中率为 ,关联查找时间为 ,内存周期时间为 1 。

    • 化简:

4. 保护与共享

  • 保护:通过在页表项中附加有效-无效位 (Valid-invalid bit)来实现 。“有效”表示页面在进程逻辑地址空间内,是合法的 。

  • 共享页:多个进程可以共享只读(可重入)代码(如编译器、文本编辑器等) 。共享代码必须在所有进程的逻辑地址空间中的相同位置出现 。

5. 高级页表结构(应对大内存)

  • 分级页表 (Hierarchical Paging):把逻辑地址空间拆分成多个页表 (如经典的 32 位机器两级页表)。

  • 哈希页表 (Hashed Page Tables):虚拟页号被哈希到页表中,表项包含一个散列到同一位置的元素链表 。

  • 反转页表 (Inverted Page Tables):内存中的每一个真实物理页只有一个表项 。包含物理内存中该页的虚拟地址和拥有它的进程信息 。优点是减少了存页表的内存,缺点是增加了搜索表的时间 。


四、 分段机制 (Segmentation):“切猪肉”式的逻辑管理

核心思想:分段是一种支持用户视角 (user view)的内存管理方案 。程序是按照逻辑单元(如主程序、子程序、函数、堆栈、数组等)来划分成一个个“段”的 。

1. 分段架构

  • 逻辑地址:由二元组组成:<段号, 偏移量> (<segment-number, offset>) 。

  • 段表 (Segment table):映射二维物理地址,包含 :

    • 基址 (base):段驻留在内存中的起始物理地址 。

    • 界限 (limit):指定该段的长度 。

  • 硬件支持段表基址寄存器 (STBR) 指向段表位置,段表长度寄存器 (STLR) 指示程序使用的段数(段号 才合法) 。

2. 分段的特性

  • 保护:段表每个条目关联验证位(=0 为非法段)和读/写/执行权限 。这使得保护机制非常自然。

  • 共享:具有相同段号的共享段可以实现代码共享,且共享发生在段级别 。

  • 内存分配:因为每个段的长度都不一样,内存分配是一个动态存储分配问题(使用 First fit / Best fit) 。

  • 缺点:分段会产生外部碎片 (external fragmentation)


五、 核心辨析:分页 vs 分段

对比维度 分页机制 (Paging) 分段机制 (Segmentation)
视角划分 系统视角:方便物理内存管理,对用户透明。 用户视角:反映程序的逻辑结构。
尺寸与碎片 固定大小:产生内部碎片 可变大小:产生外部碎片
地址维度 一维:硬件自动将单一地址拆分为页号和偏移。 二维:用户提供 <段号, 偏移量>
映射表核心 页表只需记录物理基址(帧号)。 段表必须记录基址 (base)界限 (limit)
保护与共享 较难精确按逻辑进行保护和共享。 非常容易,直接按逻辑段设置读/写/执行权限。

如果您喜欢我的文章,可以考虑打赏以支持我继续创作.

其他文章
目录导航 置顶
  1. 1. 操作系统第八章:内存管理 (Memory Management) 通关笔记
    1. 1.1. 一、 内存管理基础:程序是怎么住进内存的?
    2. 1.2. 二、 连续内存分配:一人独占一整块地
    3. 1.3. 三、 分页机制 (Paging):“切蛋糕”式的系统管理
    4. 1.4. 四、 分段机制 (Segmentation):“切猪肉”式的逻辑管理
    5. 1.5. 五、 核心辨析:分页 vs 分段
请输入关键词进行搜索