进程管理-状态转换图

前驱图

进程同步机制

进程互斥机制

信号量机制

PV操作实现前驱操作

死锁产生的必要条件


死锁的处理策略

银行家算法

存储管理

内存的分配与回收

首次适应算法

最佳适应性算法

最差适应性算法

邻近适应性算法(更加均匀)

分页存储管理

分段存储管理

一、先搞懂:分段是啥?

分页是硬件视角的划分,把内存切成固定大小的 “页框”,程序也跟着切成等大的 “页”,完全不关心程序的逻辑结构。

分段是软件视角的划分,它完全跟着程序的逻辑结构走:

  • 一个程序天然就由多个逻辑部分组成:比如主程序段、数据段、栈段、代码段、共享库段……
  • 分段存储管理,就是把这些逻辑上独立的部分,各自作为一个独立的 “段” 来管理,每个段的大小可以不一样,由它本身的逻辑大小决定。

举个生活化的例子:

  • 分页就像把一本小说强行按固定页数裁成一张张纸,不管你是章节开头还是结尾,一刀切。
  • 分段就像把小说按 “章节”“附录”“注释” 分开装订,每一部分是一个独立的段,长短由内容决定。

二、分段的地址转换逻辑

和分页类似,分段的逻辑地址也被分成两部分,但含义完全不同:逻辑地址 = 段号(S) + 段内地址(偏移量d)

  1. 段号 (S):标识这个地址属于哪个逻辑段(比如第 0 段是代码段,第 1 段是数据段)。
  2. 段内偏移量 (d):在这个段内部,距离段起始位置的字节数(和分页的 “页内偏移量” 作用类似,但它的上限是当前段的长度,不是固定的页大小)。

转换过程:

  1. 先根据段号S,查进程的段表(每个进程一张,记录每个段的基地址、长度、权限等)。
  2. 检查段内偏移量d是否超过该段的长度:
    • 若超过 → 越界错误,触发中断。
    • 若合法 → 取出该段的基地址(物理起始地址)
  3. 物理地址 = 段的基地址 + 段内偏移量d
三、分段 vs 分页:核心区别对比

表格

对比维度 分页存储管理 分段存储管理
划分依据 硬件视角,按固定大小划分,和程序逻辑无关 软件 / 用户视角,按程序的逻辑模块划分
块 / 段大小 固定(比如 4KB),所有页 / 页框大小相同 不固定,由段本身的逻辑大小决定
地址结构 页号 + 页内偏移量(偏移量上限固定) 段号 + 段内偏移量(偏移量上限由段长决定)
碎片问题 只有页内碎片(每个页最后剩下的空间,最大为页大小 - 1),无外部碎片 外部碎片(内存被不同大小的段分割后,中间留下的零散空间无法被利用),无内部碎片
共享与保护 共享和保护的粒度是 “页”,不够灵活,无法按逻辑模块单独控制 共享和保护的粒度是 “段”,天然支持按逻辑模块控制(比如代码段只读、数据段可读写)
用户可见性 页对用户透明,用户不需要知道分页的存在 段对用户可见,用户 / 编译器需要明确划分段

四、一句话总结区别
  • 分页是 “为了内存利用率”,强行把程序和内存切成固定大小的块,解决外部碎片问题,但破坏了程序的逻辑结构。
  • 分段是 “为了程序逻辑”,按模块把程序分成大小不一的段,方便共享、保护和模块化管理,但会产生外部碎片。

段页式存储管理

先分段、后分页先按程序逻辑分成若干段(像分段),再把每一个段内部,再切成固定大小的页(像分页)。兼顾分段的逻辑优点 + 分页无外部碎片的优点


一、地址结构(逻辑地址分成 3 部分)

逻辑地址 = 段号 S + 页号 P + 页内偏移 W

  • 段号:属于哪个逻辑段(代码段、数据段、栈段)
  • 页号:在这个段里面的第几页
  • 页内偏移 W:页内部第几个字节(和分页完全一样)

二、怎么转换地址(两步查表)
  1. 查段表段号 S 查段表,得到:
  • 该段的页表起始地址
  • 段长、权限、越界检查
  1. 查页表段内页号 P 去该段对应的页表,查出物理页框号

  2. 拼接物理地址物理地址 = 页框号 × 页大小 + 页内偏移 W

特点:每个段,都有自己独立的一张页表


三、三者极简对比(分页 / 分段 / 段页式)

表格

方式 划分方式 地址结构 有无外部碎片 逻辑结构
分页 系统硬性等分,跟程序逻辑无关 页号 + 页内偏移 无外部碎片,只有页内碎片 不尊重程序逻辑
分段 按程序逻辑分,段大小不等 段号 + 段内偏移 有外部碎片 完全贴合程序模块
段页式 先逻辑分段,每段再分页 段号 + 页号 + 页内偏移 无外部碎片 贴合程序逻辑

四、段页式解决了什么问题
  1. 保留分段好处:
  • 按逻辑模块划分(代码、数据、栈分离)
  • 方便按段共享、按段权限保护
  1. 保留分页好处:
  • 内存不用连续,无外部碎片
  • 内存利用率高
  1. 代价:
  • 地址转换要查两次表(段表→页表),速度慢一点
  • 硬件 MMU 更复杂

五、超通俗大白话版
  • 分页:把整本书一刀切,切成一样大的纸,不管章节。
  • 分段:把书按章节拆开,每章长短不一样,放书架要占连续位置。
  • 段页式:先按章节拆开(分段),再把每一章单独裁成一样大的小纸片(分页)既能按章节管理,又不用连续书架位置,还没零碎空位浪费。

页面置换算法

(最佳OPT)

(先进先出FIFO)

(最近最久未使用LRU)

补充

1. 普通分段 为什么有外部碎片?

纯分段:程序分好几个逻辑段(代码段、数据段、栈段)👉 每一个段,必须在物理内存里占一整块连续空间

比如:代码段要 20KB、数据段要 30KB系统必须给它找连续 20KB、连续 30KB 的整块空闲内存。

久而久之内存被切得零零碎碎:总空闲内存够,但没有一块连续大空间放一个完整段👉 这就是外部碎片,没法利用零散小空闲块。


2. 段页式 做了什么关键改变?

段页式流程:

  1. 先按逻辑分 段(代码段、数据段… 跟普通分段一样)
  2. 但是:这个段不需要物理上连续!
  3. 把这个段内部切成固定大小的页
  4. 每一个,可以放到内存任意一个零散的页框

重点一句话:✅ 段只是逻辑上的整体,物理上拆成一堆离散的页,散落放在内存各个角落


3. 为什么就能利用零散碎片?

内存里有很多零散、不连续的小空闲块(比如很多个 4KB 空位):

  • 纯分段:不行,放不下任何一个完整段,浪费
  • 段页式:我不用给你整个段分配连续空间我只需要一个一个页,随便往这些零散 4KB 空位里塞就行

👉 把大的逻辑段,拆成无数小页,吃掉所有零散碎片这就彻底消灭了外部碎片

只剩下页内碎片(每页最后一点点浪费),很小、可控。


4. 用大白话举例秒懂

假设:你要存一本「小说」(整个程序)里面分 3 章(3 个逻辑段)每一章内容很多。

  • 纯分段:每一章必须整块连在一起放书架只剩很多零散小格子,放不下一整章 → 空间浪费

  • 段页式:先分成第 1 章、第 2 章、第 3 章(分段)再把每一章撕成一张张同样大小的纸(分页)然后一张纸随便塞书架任意一个空小格子

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐