Skip to content

页表(Page Table)


一、是什么?

页表是操作系统内存管理中的核心数据结构,用于实现虚拟内存到物理内存的地址映射。在分页存储管理系统中,内存被划分为固定大小的页(通常4KB),页表存储了每个虚拟页号到物理页框号的映射关系,相当于一个"地址翻译字典"。

二、解决什么问题

  1. 内存碎片问题:消除外部碎片,提高内存利用率
  2. 内存隔离问题:防止进程相互访问内存空间(安全隔离)
  3. 大地址空间问题:允许程序使用超过物理内存的虚拟地址空间
  4. 内存共享问题:实现多个进程共享同一物理页(如共享库)

三、核心结构

页表由多个页表项(Page Table Entry, PTE) 组成,每个PTE包含:

  • 物理页框号(Frame Number)
  • 存在位(Present Bit):是否在物理内存中
  • 访问权限位(读/写/执行)
  • 修改位(Dirty Bit):是否被写入
  • 缓存禁用位等

四、应用场景

  1. 进程内存隔离:每个进程有自己的页表,实现地址空间隔离
  2. 按需分页:仅加载需要的页到内存(如Java的懒加载)
  3. 内存映射文件:文件直接映射到虚拟地址空间
  4. 共享内存:多个进程共享同一物理页(如Java NIO的MappedByteBuffer)
  5. 写时复制:父子进程共享只读页,写入时复制新页

五、Java示例(内存映射文件)

java
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class PageTableDemo {
    public static void main(String[] args) throws Exception {
        try (RandomAccessFile file = new RandomAccessFile("data.bin", "rw");
             FileChannel channel = file.getChannel()) {
            
            // 创建内存映射(利用页表机制)
            MappedByteBuffer buffer = channel.map(
                FileChannel.MapMode.READ_WRITE,  // 读写权限
                0,                               // 起始位置
                1024 * 1024                      // 映射大小(1MB)
            );
            
            // 直接操作映射内存
            buffer.put(0, (byte) 0x41); // 写入'A'
            System.out.println((char) buffer.get(0)); // 读取并打印
        }
    }
}

六、重要注意事项

  1. TLB(快表):CPU缓存常用页表项,加速地址转换
  2. 多级页表:解决大地址空间下的页表内存占用问题(如x86四级页表)
  3. 缺页中断:访问不在内存的页会触发OS加载页面
  4. 内存开销:页表本身占用内存(64位系统更显著)
  5. 安全风险:页表漏洞可能导致特权提升(如Meltdown漏洞)

七、总结

页表是现代操作系统的内存管理基石,通过虚拟地址到物理地址的映射,解决了内存碎片、进程隔离和地址空间扩展等核心问题。在Java开发中,虽然开发者不直接操作页表,但JVM的垃圾回收、内存映射文件(NIO)等机制都深度依赖页表实现。理解页表有助于诊断内存相关异常(如OOM)和优化程序内存使用。

💡 知识扩展:Java 15引入的ZGC垃圾回收器使用多映射页表技术,允许同一物理页映射到多个虚拟地址,显著减少STW(Stop-The-World)时间。