1.线程
- 传统的进程有两个属性:可拥有资源的独立单位; 可独立调度和分配的基本单位。
- 引入线程的原因是进程在创建、撤销和切换中,系统必须为之付出较大的时
空开销,故在系统中设置的进程数目不宜过多,进程切换的频率不宜太高,
就限制了并发程度的提高。引入线程后,将传统进程的两个基本属性分开,线
程作为调度和分配的基本单位,进程作为独立分配资源的单位。用户可以通过
创建线程来完成任务,以减少程序并发执行时付出的时空开销。 - 线程是进程中的一个实体,是被系统独立分配和调度的基本单位。线程基本
上不拥有资源,只拥有一点运行中必不可少的资源如程序计数器、一组寄存
器和栈),它可与同属一个进程的其他线程共享进程所拥有的全部资源,例如
进程的公共数据、全局变量、代码、文件等资源,但不能共享线程独有的资源
如线程的栈指针等标识数据。
2.分区存储管理
所谓分区存储组织,就是整存,将某进程运行所需的内存整体一起分配给它
然后再执行。有三种分区方式:
-
固定分区:静态分区方法,将主存分为若干个固定的分区,将要运行的作业
装配进去,由于分区固定,大小和作业需要的大小不同,会产生内部碎片。
-
可变分区:动态分区方法,主存空间的分区是在作业转入时划分,正好划分
为作业需要的大小,这样就不存在内部碎片,但容易将整片主存空间切割成许
多块,会产生外部碎片。可变分区的算法如下:
- 首次适应法:按内存地址顺序从头查找,找到第一个>=9K空间的空闲块,即
切割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 优点
-
内存利用率高 :
相比于连续分配(如分区分配),分页消除了外部碎片(External Fragmentation),只存在最多一页的内部碎片(Internal Fragmentation)。
-
分配与回收简单 :
物理内存以页框为单位管理,分配时只需找到空闲页框,无需考虑连续性。
-
支持虚拟内存 :
分页是实现虚拟内存的基础,允许程序使用比物理内存更大的地址空间。
3.3 缺点
-
系统开销增加:
- 需要维护页表,占用内存;
- 每次地址转换需查页表(可通过 TLB 缓解);
- 若采用多级页表,地址转换更复杂。
-
可能发生抖动 (Thrashing):
当进程频繁发生缺页中断,且系统忙于页面换入换出而无法有效执行进程时,系统效率急剧下降,称为"抖动"。
-
页表可能很大 :
对于大地址空间(如 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
- 低 12 位:
💡 更简单方法:
公式:
页号 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)
- 10879 = 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 完全一致。
⚠️ 重要前提条件
这种"二进制拼接"成立,必须满足:
- 页面大小是 2 的整数次幂(所有现代系统都满足);
- 偏移位数 = log₂(页面大小);
- 物理块号和偏移之间无重叠、无进位(因为偏移 < 页面大小,所以不会溢出到高位)。
只要满足这些,"块号 << 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
检查位数:10101001101 共 11 位 ✅
(如果不足 11 位,需在前面补 0)
所以:
- 页内偏移(11 位) =
10101001101
第三步:将物理块号转为二进制
- 物理块号 = 6
- 二进制 =
110
注意:块号位数没有固定限制,根据系统地址空间决定。这里只需足够表示即可。
第四步:二进制位拼接(关键步骤)
因为偏移占 低 11 位,所以:
物理地址(二进制) = [物理块号] [页内偏移(11位)]
= 110 10101001101
拼接结果:
11010101001101
现在我们来分组以便转换为十六进制(从右往左每 4 位一组):
原串:11 0101 0100 1101
补前导0成整字节:0011 0101 0100 1101
→ 十六进制:
0011= 30101= 50100= 41101= 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(内存管理单元)在硬件层面进行地址转换的基本原理!