当你的电脑同时运行十几个程序时,它们如何和谐共享有限的内存空间?为什么程序可以使用比物理内存更大的地址?这一切都归功于操作系统的分段分页技术——内存管理的两大支柱!

在这里插入图片描述

一、内存管理:计算机的"房地产经纪人"

想象一个繁忙的城市:

  • 🏢 建筑物 = 内存块
  • 👨‍💼 居民 = 程序和数据
  • 📐 分段 = 按功能划分区域(住宅区、商业区)
  • 📄 分页 = 标准化公寓单元(统一户型)

在这里插入图片描述

二、分段:逻辑视角的内存管理

1. 什么是分段?

  • 按逻辑单元划分内存:代码段、数据段、堆栈段
  • 类似书籍的章节结构
    • 第一章:代码段
    • 第二章:数据段
    • 第三章:堆栈段

在这里插入图片描述

2. 分段地址转换

在这里插入图片描述

段寄存器示例

mov ax, 0x1000   ; 设置数据段
mov ds, ax
mov si, 0x200    ; 偏移地址
mov al, [ds:si]  ; 访问物理地址 0x1000*16 + 0x200 = 0x10200

3. 分段优缺点

优点 缺点
逻辑清晰,符合程序结构 内存碎片问题严重
自然的内存保护机制 内存分配不够灵活
简化共享(共享代码段) 最大段大小受限
支持动态链接 需要连续物理内存

三、分页:物理视角的内存管理

1. 什么是分页?

  • 固定大小的内存块:通常4KB(x86)
  • 虚拟页到物理页框的映射
  • 类似活页笔记本
    • 目录 = 页表
    • 页码 = 虚拟页号
    • 实际页 = 物理页框

在这里插入图片描述

2. 分页地址转换(32位系统)

在这里插入图片描述

3. 页表项结构

31-12      9-11     8    7    6    5    4    3    2    1    0
+-------------------+-----+----+----+----+----+----+----+----+
|   页框基址        | AVL | G | PS | D | A | PCD| PWT| U/S| R/W| P |
+-------------------+-----+----+----+----+----+----+----+----+----+
  • P:存在位(1=在内存中)
  • R/W:读写权限
  • U/S:用户/超级用户
  • A:访问位
  • D:脏位(已修改)

4. 分页优缺点

优点 缺点
解决外部碎片问题 页表占用额外内存
支持虚拟内存 地址转换开销大
灵活的权限控制 可能引起内部碎片
内存分配更高效 TLB未命中影响性能

四、分段 vs 分页:终极对决

特性 分段 🧩 分页 📄
划分单位 逻辑模块(代码/数据) 固定大小页(通常4KB)
碎片问题 外部碎片严重 只有内部碎片
地址转换 基址+偏移量 多级页表映射
内存共享 段级共享 页级共享
虚拟内存 不支持 核心支持
硬件支持 段寄存器 MMU/TLB
现代应用 基本淘汰 所有现代OS的核心
优势场景 嵌入式系统 通用计算系统

五、现代解决方案:段页式内存管理

在这里插入图片描述

x86架构实现

  1. 逻辑地址 → 段基址 + 偏移 = 线性地址
  2. 线性地址 → 页表查询 → 物理地址

保护模式代码示例

; 设置段描述符
mov eax, ds_base
mov ebx, ds_limit
mov ecx, 0x92       ; 数据段,可读写
call set_descriptor

; 设置页目录
mov eax, page_dir_base
mov cr3, eax        ; 加载页目录基址

; 启用分页
mov eax, cr0
or eax, 0x80000000  ; 设置PG位
mov cr0, eax

六、分页进阶:多级页表与TLB

1. 64位系统的四级页表

在这里插入图片描述

2. TLB(转换后备缓冲器)

在这里插入图片描述

TLB性能影响
在这里插入图片描述

七、动手实验:模拟地址转换

分页地址转换Python模拟

def page_translate(virtual_addr, page_table):
    # 32位地址:前20位页号,后12位偏移
    page_num = virtual_addr >> 12
    offset = virtual_addr & 0xFFF
    
    if page_num in page_table:
        # TLB命中
        frame = page_table[page_num]
        physical_addr = (frame << 12) | offset
        print(f"虚拟地址 0x{virtual_addr:08X} → 物理地址 0x{physical_addr:08X}")
        return physical_addr
    else:
        # 触发缺页异常
        print(f"缺页异常!页面 0x{page_num:05X} 不在内存中")
        return None

# 测试
page_table = {0x1000: 0x300, 0x1001: 0x301}  # 页表映射
page_translate(0x10001234, page_table)  # 输出:虚拟地址 0x10001234 → 物理地址 0x3010234

分段地址转换模拟

def segment_translate(logical_addr, segment_table):
    selector = logical_addr >> 16
    offset = logical_addr & 0xFFFF
    
    if selector in segment_table:
        base, limit = segment_table[selector]
        if offset <= limit:
            physical_addr = base + offset
            print(f"逻辑地址 0x{logical_addr:08X} → 物理地址 0x{physical_addr:08X}")
            return physical_addr
        else:
            print(f"段越界错误!偏移 {offset} 超出段限制 {limit}")
            return None
    else:
        print(f"无效段选择符:0x{selector:04X}")
        return None

# 测试
segment_table = {0x10: (0x10000, 0xFFFF)}  # 段基址0x10000,限制0xFFFF
segment_translate(0x10001234, segment_table)  # 输出:逻辑地址 0x10001234 → 物理地址 0x11234

八、现代内存管理技术演进

在这里插入图片描述

九、总结:选择正确的内存管理

场景 推荐方案 原因
现代通用操作系统 纯分页 虚拟内存支持,灵活性高
嵌入式实时系统 分段 简单确定,开销小
高性能计算 分页+大页 减少TLB缺失
虚拟化环境 嵌套分页 减少虚拟机切换开销
安全关键系统 分段+分页 多层保护机制

💡 核心洞见

  1. 分段提供逻辑隔离,分页提供物理灵活
  2. 现代操作系统主要使用分页
  3. TLB是分页性能的关键
  4. 段页结合提供最大灵活性

思考题:为什么64位系统基本放弃了分段机制?评论区分享你的见解!

🚀 动手实验:在Linux中查看分页信息:

# 查看页大小
getconf PAGESIZE

# 查看内存映射
cat /proc/self/maps

# 查看TLB状态
perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses ls

理解分段和分页,你就掌握了操作系统内存管理的核心魔法!现在打开你的任务管理器,看看那些正在被精心管理的内存区域吧!

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐