线程和分区存储管理以及逻辑页

1.线程

  • 传统的进程有两个属性:可拥有资源的独立单位; 可独立调度和分配的基本单位。
  • 引入线程的原因是进程在创建、撤销和切换中,系统必须为之付出较大的时
    空开销,故在系统中设置的进程数目不宜过多,进程切换的频率不宜太高,
    就限制了并发程度的提高。引入线程后,将传统进程的两个基本属性分开,线
    程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过
    创建线程来完成任务,以减少程序并发执行时付出的时空开销。
  • 线程是进程中的一个实体,是被系统独立分配和调度的基本单位。线程基本
    上不拥有资源,只拥有一点运行中必不可少的资源如程序计数器、一组寄存
    器和栈),它可与同属一个进程的其他线程共享进程所拥有的全部资源,例如
    进程的公共数据、全局变量、代码、文件等资源,但不能共享线程独有的资源
    如线程的栈指针等标识数据。

2.分区存储管理

所谓分区存储组织,就是整存,将某进程运行所需的内存整体一起分配给它

然后再执行。有三种分区方式:

  • 固定分区:静态分区方法,将主存分为若干个固定的分区,将要运行的作业

    装配进去,由于分区固定,大小和作业需要的大小不同,会产生内部碎片。

  • 可变分区:动态分区方法,主存空间的分区是在作业转入时划分,正好划分

    为作业需要的大小,这样就不存在内部碎片,但容易将整片主存空间切割成许

    多块,会产生外部碎片。可变分区的算法如下:

    • 首次适应法:按内存地址顺序从头查找,找到第一个>=9K空间的空闲块,即
      切割9K空间分配给进程。
    • 最佳适应法:将内存中所有空闲内存块按从小到大排序,找到第一个>=9K空
      间的空闲块,切割分配,这个将会找到与9K空间大小最相近的空闲块。
    • 最差适应法:和最佳适应法相反,将内存中空闲块空间最大的,切割9K空间
      分配给进程,这是为了预防系统中产生过多的细小空闲块。
    • 循环首次适应法:按内存地址顺序查找,找到第一个>=9K空间的空闲块,而
      后若还需分配,则找下一个,不用每次都从头查找,这是与首次适应法不同的
      地方
  • 系统分配内存的算法有很多,如下图所示,根据分配前的内存情况,还需要

    分配9K空间,对不同算法的结果介绍如下:

  • 可重定位分区:可以解决碎片问题,移动所有已经分配好的区域,使其成为

    一个连续的区域,这样其他外部细小的分区碎片可以合并为大的分区,满足作

    业要求。只在外部作业请求空间得不到满足时进行

3.逻辑页

逻辑页分为页号和页内地址,页内地址就是物理偏移地址,而页号与物理块号并非按序对应的,需要查询页表,才能得知页号对应的物理块号,再用物理块号加上偏移地址才得出了真正运行时的物理地址。

  • 优点:利用率高,碎片小,分配及管理简单
  • 缺点:增加了系统开销,可能产生抖动现象

3.1 分页机制的基本原理

在分页存储管理中,逻辑地址空间被划分为固定大小的"页" (Page),而物理内存被划分为同样大小的"页框" (Page Frame,也称物理块)。

逻辑地址由两部分组成:

  • 页号(Page Number):用于索引页表,查找对应的物理块号;
  • 页内偏移(Page Offset):表示在该页内的字节偏移量,与物理页框内的偏移一致。

例如,若页面大小为 4KB(即 (2^{12}) 字节),则逻辑地址的低 12 位为页内偏移,高位为页号。

通过页表 (Page Table)将逻辑页号映射到物理页框号,最终物理地址 = 物理块号 × 页面大小 + 页内偏移

1. 页面大小决定 偏移位数,不决定整个地址长度
  • 页面大小 = 4KB = (2^{12}) 字节
    → 要寻址一页内的任意字节,需要 12 位(因为 (2^{12} = 4096) 个不同偏移)。
  • 所以:页内偏移 = 逻辑地址的低 12 位
2. 逻辑地址总长度由 CPU 架构 / 虚拟地址空间 决定
  • 32 位系统 中,逻辑地址是 32 位
  • 64 位系统 中,逻辑地址通常是 48 位有效(如 x86-64),但理论上可达 64 位。

✅ 因此:

  • 页号位数 = 总地址位数 - 12
    • 32 位系统:页号占 20 位(32 - 12 = 20)→ 最多 (2^{20}) 个页(约 4GB 地址空间)
    • 48 位虚拟地址:页号占 36 位(48 - 12 = 36)→ 巨大的虚拟空间

📌 举个例子(32 位系统)

假设逻辑地址是 32 位,页面大小 4KB:

复制代码
逻辑地址(32 位):
|     页号(20 位)     |   页内偏移(12 位)   |

例如逻辑地址:0x0000_3A7F(十六进制)

  • 二进制(32 位):

    复制代码
    0000 0000 0000 0000 0011 1010 0111 1111
    ↑____________________↑ ↑_______________↑
          页号(20位)         偏移(12位)
  • 页号 = 高 20 位 = 0x00003 = 3

  • 偏移 = 低 12 位 = 0xA7F = 2687

即使地址看起来"很小"(如 0x3A7F 只用了 16 位),在 32 位系统中它仍然是一个 32 位地址,高位补 0。


✅ 总结

概念 说明
页面大小 = 4KB = (2^{12}) → 页内偏移必须用 12 位
逻辑地址总长度(如 32/64 位) → 由 CPU 和 OS 决定
页号位数 = 总地址位数 − 12
即使地址值很小(如 0x3A7F) → 在 32 位系统中仍视为 32 位,高位为 0,属于页号部分

3.2 优点

  1. 内存利用率高

    相比于连续分配(如分区分配),分页消除了外部碎片(External Fragmentation),只存在最多一页的内部碎片(Internal Fragmentation)。

  2. 分配与回收简单

    物理内存以页框为单位管理,分配时只需找到空闲页框,无需考虑连续性。

  3. 支持虚拟内存

    分页是实现虚拟内存的基础,允许程序使用比物理内存更大的地址空间。


3.3 缺点

  1. 系统开销增加

    • 需要维护页表,占用内存;
    • 每次地址转换需查页表(可通过 TLB 缓解);
    • 若采用多级页表,地址转换更复杂。
  2. 可能发生抖动 (Thrashing):

    当进程频繁发生缺页中断,且系统忙于页面换入换出而无法有效执行进程时,系统效率急剧下降,称为"抖动"。

  3. 页表可能很大

    对于大地址空间(如 64 位系统),页表可能占用大量内存,因此常采用多级页表、反向页表或哈希页表等优化结构。


3.4 补充说明

  • 页表项(PTE)通常包含:物理页框号、有效位、访问位、修改位、保护位等。
  • 快表(TLB, Translation Lookaside Buffer)是一种高速缓存,用于加速页表查询。
  • 现代操作系统(如 Linux、Windows)普遍采用分页机制,并结合分段或纯分页实现虚拟内存管理。

✅ 总结:你对分页机制的理解是正确的。它通过"页号 → 页表 → 物理块号 + 偏移"的方式实现地址转换,在提高内存利用率的同时,也带来了额外的管理和性能开销。合理设计页表结构和页面置换算法,是平衡性能与资源的关键。

当然可以!下面是一个典型的软考(系统分析师/软件设计师/网络工程师等)真题风格的例题 ,涉及分页存储管理中逻辑地址到物理地址的转换过程,并附有详细解析。


3.5 📌【软考真题示例】

某系统采用分页存储管理 ,页面大小为 4KB。设某进程的页表如下:

页号 物理块号
0 5
1 10
2 8
3 2

若该进程访问的逻辑地址为 0x3A7F (十六进制),则对应的物理地址是多少?(用十六进制表示)


✅【解题步骤】

第一步:确定页面大小,计算页内偏移位数
  • 页面大小 = 4KB = (4 \times 1024 = 4096 = 2^{12}) 字节
  • 所以,页内偏移占低 12 位(因为 (2^{12} = 4096),可寻址 0~4095)。
  • 也就是说,逻辑地址的高若干位是页号,低 12 位是页内偏移

第二步:将逻辑地址 0x3A7F 转换为二进制或直接分析
  • 0x3A7F 是十六进制,先转为二进制(每1位十六进制 = 4位二进制):

    复制代码
    3   A   7   F
    0011 1010 0111 1111
    → 共 16 位:0011 1010 0111 1111
  • 低 12 位是页内偏移:

    • 低 12 位:1010 0111 1111(即后三位十六进制 A7F)
    • 高 4 位(16 - 12 = 4)是页号:0011 = 3

💡 更简单方法:

公式:

页号 P = 逻辑地址 / 页大小 (取整)

页内偏移量 W = 逻辑地址 % 页大小 (取余)

由于 4KB = (2^{12}),所以
页号 = 逻辑地址 ÷ 4096 (整除)
页内偏移 = 逻辑地址 mod 4096

  • 0x3A7F = 十进制:

    (3 \times 16^3 + 10 \times 16^2 + 7 \times 16 + 15 = 3 \times 4096 + 10 \times 256 + 112 + 15 = 12288 + 2560 + 127 = 14975)

  • 页号 = (14975 ÷ 4096 = 3)(因为 (3 \times 4096 = 12288),(4 \times 4096 = 16384 > 14975))

  • 页内偏移 = (14975 - 12288 = 2687)

验证:0xA7F = (10 \times 256 + 7 \times 16 + 15 = 2560 + 112 + 15 = 2687) ✅

所以:

  • 页号 = 3
  • 页内偏移 = 0xA7F

第三步:查页表,找物理块号

根据题目页表:

页号 物理块号
3 2

→ 页号 3 对应 物理块号 = 2


第四步:计算物理地址
  • 物理地址 = 物理块号 × 页面大小 + 页内偏移
  • = (2 \times 4096 + 2687 = 8192 + 2687 = 10879)

转为十六进制:

  • 10879 ÷ 16:
    • 10879 = 0x2A7F
      (因为 2×4096=0x2000,加上 0xA7F → 0x2000 + 0xA7F = 0x2A7F

🔍 快速技巧:

物理块号 = 2 → 物理块起始地址 = 2 × 4KB = 0x2000

偏移 = 0xA7F

所以物理地址 = 0x2000 + 0xA7F = 0x2A7F


✅ 最终答案:

物理地址为 0x2A7F


📚【考点总结】(软考常考)

  • 页面大小决定偏移位数(如 4KB → 12 位偏移);
  • 逻辑地址拆分为 页号 + 页内偏移
  • 通过页表查得物理块号;
  • 物理地址 = 块号 × 页面大小 + 偏移
  • 熟练掌握十六进制、二进制、十进制转换;
  • 注意:页表只记录"页号→块号"映射,偏移不变

3.6 可以使用二进制位拼接法来构造物理地址

是的!可以使用二进制位拼接法来构造物理地址,但必须满足一个前提:

"拼接"实质是:将物理块号左移(偏移位数)后,与页内偏移进行按位或(或直接相加),这在二进制层面等价于"高位放块号,低位放偏移"的拼接。


✅ 正确理解:"二进制位拼接"是合法且常用的

在分页系统中,由于:

  • 页面大小 = (2^n) 字节(如 4KB = (2^{12}))
  • 页内偏移正好占 低 n 位
  • 物理块号表示的是"第几个页框",其对应的起始地址为 块号 × 2^n,即 块号左移 n 位

因此,物理地址的二进制形式就是:

复制代码
[ 物理块号(二进制) ] [ 页内偏移(n 位,不足补前导0) ]

这就是所谓的 "二进制位拼接"


📌 举例说明(原题回顾)

  • 页面大小 = 4KB = (2^{12}) → 偏移占 12 位
  • 物理块号 = 2 → 二进制:10
  • 页内偏移 = 0xA7F = 1010 0111 1111(12 位)

拼接过程(二进制):

复制代码
块号(2)      →        10
偏移(0xA7F)  → 1010 0111 1111
拼接后         → 10 1010 0111 1111
                ↑↑ ↑↑↑↑ ↑↑↑↑ ↑↑↑↑
                这就是物理地址的二进制

转换为十六进制:

  • 10 1010 0111 1111 → 分组:0010 1010 0111 1111(前面补0凑整字节)
  • = 0x2A7F

这和 2 × 4096 + 0xA7F = 0x2000 + 0xA7F = 0x2A7F 完全一致。


⚠️ 重要前提条件

这种"二进制拼接"成立,必须满足:

  1. 页面大小是 2 的整数次幂(所有现代系统都满足);
  2. 偏移位数 = log₂(页面大小)
  3. 物理块号和偏移之间无重叠、无进位(因为偏移 < 页面大小,所以不会溢出到高位)。

只要满足这些,"块号 << n | 偏移" 就等于二进制拼接 ,也等于 块号 × 页面大小 + 偏移


❌ 不能做什么?

  • 不能用十进制或十六进制字符串直接拼接

    比如块号=10(十进制),偏移=0x123,不能写成 "10"+"123" = "10123" ------ 这毫无意义。

  • 不能忽略位宽对齐

    块号必须左移到正确位置,偏移必须用足 n 位(不足补前导0)。


✅ 总结

方法 是否可行 说明
二进制位拼接(块号左移 + 偏移) ✅ 可行,且本质正确 实际就是地址计算的位运算形式
数值计算块号 × 页面大小 + 偏移 ✅ 可行,最通用 推荐用于理解和考试
十六进制/十进制字符串拼接 ❌ 不可行 仅在特定小数值下巧合成立,逻辑错误

💡 在软考、操作系统课程或面试中,说"将物理块号和页内偏移在二进制下拼接形成物理地址"是完全正确的,只要你理解这是基于"左移+或"操作,而不是字符串操作。


下面举一个 页面大小为 2KB(即 (2^{11}) 字节) 的例子,此时 页内偏移占 11 位 ,我们通过 二进制位拼接法 构造物理地址,并验证其正确性。


📌 题目设定

  • 页面大小 = 2KB = 2048 = (2^{11}) 字节
    → 页内偏移 = 低 11 位
  • 某进程的页表中:逻辑页号 5 对应物理块号 = 6
  • 现在访问该页内的偏移地址:1357(十进制)

✅ 问题:求对应的物理地址 (用十进制和十六进制表示),并用二进制位拼接法演示过程。


第一步:确认页内偏移 ≤ 页面大小

  • 偏移 = 1357
  • 页面大小 = 2048
  • 1357 < 2048 → 合法 ✅

第二步:将偏移转换为 11 位二进制

1357 的二进制:

复制代码
1357 ÷ 2 = ...
→ 1357 = 1024 + 256 + 64 + 8 + 4 + 1
       = 2^10 + 2^8 + 2^6 + 2^3 + 2^2 + 2^0
→ 二进制:10101001101

检查位数:1010100110111 位

(如果不足 11 位,需在前面补 0)

所以:

  • 页内偏移(11 位) = 10101001101

第三步:将物理块号转为二进制

  • 物理块号 = 6
  • 二进制 = 110

注意:块号位数没有固定限制,根据系统地址空间决定。这里只需足够表示即可。


第四步:二进制位拼接(关键步骤)

因为偏移占 低 11 位,所以:

复制代码
物理地址(二进制) = [物理块号] [页内偏移(11位)]
                   =     110     10101001101

拼接结果:

复制代码
11010101001101

现在我们来分组以便转换为十六进制(从右往左每 4 位一组):

复制代码
原串:11 0101 0100 1101
补前导0成整字节:0011 0101 0100 1101

→ 十六进制:

  • 0011 = 3
  • 0101 = 5
  • 0100 = 4
  • 1101 = D

所以:物理地址 = 0x354D


第五步:用数值法验证

公式:
物理地址 = 物理块号 × 页面大小 + 页内偏移

= (6 \times 2048 + 1357)

= (12288 + 1357 = 13645)

将 13645 转换为十六进制:

  • 13645 ÷ 16 = 852 余 13 (D)
  • 852 ÷ 16 = 53 余 4
  • 53 ÷ 16 = 3 余 5
  • 3 ÷ 16 = 0 余 3
    → 从下往上:0x354D

再转回二进制验证:

  • 0x354D = 0011 0101 0100 1101 = 11010101001101(去掉前导0)
  • 高位 110 = 6(块号)
  • 低位 10101001101 = 1357(偏移)✅

完全一致!


✅ 最终答案

  • 物理地址(十进制):13645

  • 物理地址(十六进制):0x354D

  • 二进制拼接过程

    复制代码
    块号(6)      → 110
    偏移(1357)   → 10101001101 (11位)
    拼接           → 11010101001101 = 0x354D

🔍 关键总结

  • 当页面大小 = (2^n) 字节时,页内偏移占低 n 位
  • 物理地址 = (块号 << n) | 偏移,在二进制上等价于"高位块号 + 低位偏移"的拼接;
  • 这种拼接必须按位对齐 ,且偏移必须用足 n 位(不足补前导 0);
  • 本例中 n = 11,所以偏移严格占 11 位,拼接才正确。

💡 这正是 CPU 的 MMU(内存管理单元)在硬件层面进行地址转换的基本原理!