什么是分段和分页?

#计算机网络#操作系统#面试八股

什么是分段和分页?

两者都是把虚拟地址翻译成物理地址的方案:分段按程序的逻辑结构(代码段、数据段、栈段)切成变长的块, 分页把地址空间切成固定大小的页(常见 4KB)。分段贴近程序员视角但会产生外部碎片, 分页消除外部碎片但要靠多级页表 + TLB 才能查得快。现代 x86-64 实际上以分页为主,分段只留下最小化的段基址。

1. 两种映射

分段(segment):
  逻辑地址 = [段号 s][段内偏移 d]
  段表[s] = {基址 base, 限长 limit}
  物理地址 = base + d      (d 必须 < limit,否则段错误)

分页(paging):
  虚拟地址 = [页号 p][页内偏移 d]
  页表[p] → 物理页框号 f
  物理地址 = f × 页大小 + d

x86-64 的实际路径(段页式):
  段寄存器(基址≈0) ─► 线性地址 ─► PML4 → PDPT → PD → PT(4 级)─► 物理地址
                                 每级 9 位索引 + 页内 12 位偏移 = 48 位
虚拟地址 48 位:
┌────────┬────────┬────────┬────────┬────────────┐
│ PML4 9 │ PDPT 9 │  PD  9 │  PT  9 │ offset 12  │
└────────┴────────┴────────┴────────┴────────────┘
   每级页表 512 项 × 8 字节 = 4KB,正好一页

2. 对比

维度分段分页
划分依据逻辑意义(代码/数据/栈)物理固定大小
块大小变长固定(4KB,可 2MB/1GB 大页)
碎片外部碎片(空洞难利用)内部碎片(最后一页浪费)
对程序员可见可见(段错误、段权限)透明
表项内容基址 + 限长 + 保护位页框号 + 权限 + 脏位/访问位
共享与保护按段共享按页共享(COW、mmap)
换入换出整段,粒度粗按页,粒度细

分页解决了"外部碎片",代价是"内部碎片":一个 1 字节的文件也占一页 4KB; 同时页表本身要占内存,32 位单级页表要 4MB,64 位单级页表则完全不可行,所以必须多级。

3. 多级页表省在哪

32 位、4KB 页、单级页表:
  2^20 个页表项 × 4B = 4MB,每个进程都要一份

64 位、4 级页表:
  只给"实际用到的地址区间"分配下级页表
  一个只用了 3 个页的进程,只需 1 个 PML4 + 1 个 PDPT + 1 个 PD + 1 个 PT ≈ 16KB

代价是一次地址翻译要访存 4 次(每级一次),于是有了 TLB(Translation Lookaside Buffer): 把最近的页表项缓存在 CPU 里,命中就只需 1 个周期;未命中才走"页表遍历"(page walk),慢几十倍。 这也是为什么上下文切换、大内存随机访问会变慢——TLB 被刷或被挤掉。

4. 观测与调优

getconf PAGE_SIZE                 # 4096
cat /proc/meminfo | grep -i huge  # 大页池与使用情况

# 看进程的虚拟地址段(哪些是映射文件、哪些是匿名页)
cat /proc/$$/maps | head

# 打开透明大页(THP),减少 TLB miss
echo always > /sys/kernel/mm/transparent_hugepage/enabled

# 预留 2MB 大页给数据库
echo 1024 > /proc/sys/vm/nr_hugepages
// 显式申请大页,减少 TLB 压力(2MB 一页,TLB 覆盖范围放大 512 倍)
void *p = mmap(NULL, 2 * 1024 * 1024, PROT_READ | PROT_WRITE,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);

5. 常见追问

Q:为什么页大小是 4KB? 历史折中:页太小页表项爆炸、IO 次数多;页太大内部碎片严重、内存浪费。 4KB 与磁盘块、页表项大小(512×8B)刚好对齐,硬件实现也简单。

Q:缺页中断(page fault)流程? CPU 访问的页不在内存 → 触发缺页异常 → 内核检查地址合法性 → 分配页框 → 从磁盘/交换区读入 → 更新页表 → 返回用户态重新执行那条指令。非法地址则发 SIGSEGV。

Q:fork 之后为什么很快? 因为用了写时复制(Copy-On-Write):父子共享同一批物理页并全部标只读, 任何一方写入才触发缺页,此时才真正复制那一页。这也是"分页按页共享"的直接收益。

Q:段错误和缺页是一回事吗? 不是。缺页是"页不在内存",可能合法(按需加载)也可能非法;段错误(SIGSEGV)是访问了无权限或未映射的地址, 属于非法缺页的最终结果。

小结

分段是"按逻辑切、变长、有外部碎片",分页是"按固定大小切、透明、有内部碎片"。 现代系统用多级页表 + TLB + 大页把分页的开销压下去,分段退化为权限检查的辅助手段。 答题顺序:两种映射 → 碎片与页表空间 → TLB 与缺页 → COW 与大页。

笔记加载中…