非连续内存分配
一、分段机制的核心原理
1. 逻辑地址空间的划分(图片左侧)
- 程序被拆分为多个功能模块,每个模块对应一个段:
- 堆(Heap):动态内存分配区(如
malloc
申请的空间)。 - 运行栈(Stack):函数调用栈(局部变量、返回地址)。
- 程序数据(Data):全局变量、静态数据区。
- 程序text段(Text):代码指令区(机器码)。
- 堆(Heap):动态内存分配区(如
- 特点:
- 每个段有独立的功能和访问权限(如text段只读,栈段可读写)。
- 逻辑地址由
段号 + 段内偏移
组成(如段2: 偏移100
)。
2. 物理内存的分散映射(图片右侧)
- 物理内存中,每个段被分配到独立的非连续区域:
- 堆段 → 物理堆区
- 栈段 → 物理栈区
- 数据段 → 物理数据区
- text段 → 物理代码区(可能与库代码共享)
二、分段机制的实现流程
二、段访问的两种实现方案
方案1:段寄存器 + 地址寄存器(左侧示意图)
- 硬件支持:
- 段寄存器(Segment Register):存储当前段号
s
(如s = n₂
)。 - 地址寄存器(Address Register):存储段内偏移
addr
。
- 段寄存器(Segment Register):存储当前段号
- 工作流程:
- CPU 执行指令时,将逻辑地址
(s, addr)
拆解:s
存入段寄存器。addr
存入地址寄存器。
- 硬件自动转换:
- 通过段表(Segment Table)查询段号
s
对应的基址(Base Address) 和段长(Limit)。 - 检查偏移
addr
是否合法(addr ≤ Limit
)。 - 物理地址 = 基址 + addr。
- 通过段表(Segment Table)查询段号
- CPU 执行指令时,将逻辑地址
方案2:单地址实现方案(右侧示意图)
- 硬件支持:
- 单一地址寄存器:存储拼接后的地址(将
s
和addr
合并为一个值)。
- 单一地址寄存器:存储拼接后的地址(将
- 工作流程:
- 逻辑地址
(s, addr)
被编码为单值(如高比特位 =s
,低比特位 =addr
)。- 示例:32位地址 = 高16位存
s
+ 低16位存addr
。
- 示例:32位地址 = 高16位存
- 软件/硬件转换:
- 方式1(软件):操作系统截取高比特位作为
s
,查段表获取基址,再与低比特位addr
相加。 - 方式2(硬件):MMU 自动拆分
s
和addr
,通过段表转换(类似方案1)。
- 方式1(软件):操作系统截取高比特位作为
- 逻辑地址
地址转换流程
- 逻辑地址生成:
CPU执行程序P时产生逻辑地址(如段号=2, 偏移=500
)。 - 段表查询:
MMU以段号为索引查段表 → 获取该段的基址(Base)和段限(Limit)。
示例:段号2对应Base=1000, Limit=1500
- 越界检查:
- 若偏移 ≤ Limit(如500 ≤ 1500)→ 继续下一步。
- 若偏移 > Limit(如2000 > 1500)→ 触发内存异常(Memory Exception)。
- 物理地址计算:
物理地址 = Base + 偏移(如1000 + 500 = 1500
)。 - 内存访问:
CPU通过物理地址1500访问程序P所在段的数据。
操作系统的核心作用
1. 段表管理:内存映射的构建者
- 初始化段表:
OS在程序加载时为每个段分配物理内存,填写段表项(Base/Limit)。
示例:将程序P的代码段映射到物理地址1000-2500,段表项设为Base=1000, Limit=1500
。 - 动态更新:
若程序申请扩展堆/栈空间,OS分配新内存并更新段表(如增大Limit)。
2. 内存异常处理:安全的守护者
- 拦截非法访问:
当MMU检测到偏移越界(如偏移=2000 > Limit=1500),触发异常交由OS处理。 - 响应策略:
- 终止进程:若为恶意访问(如缓冲区溢出攻击),强制终止程序。
- 扩展段空间:若为合法需求(如栈增长),分配新内存并更新段表。
3. 物理内存分配:资源的调度者
- 分配连续块:
OS为每个段分配连续的物理内存区域(如图中程序P的段占1000-2500)。 - 碎片管理:
通过段表实现非连续分配(不同段可分散存放),减少外部碎片。
4. 权限控制:隔离的保障
- 段表扩展功能:
实际段表项通常包含权限位(如RWX),OS设置权限防止非法操作。
示例:代码段设为只读(R),阻止篡改指令。