Linux内存映射
概述
深入理解虚拟地址到物理地址的转换机制
什么是内存映射?
内存映射(Memory Mapping)是Linux系统中最核心的概念之一。它是虚拟地址空间与物理内存之间的桥梁,负责将程序使用的虚拟内存地址 映射为 实际的物理内存地址。
核心概念: 每个进程都有自己的虚拟地址空间,通过页表(Page Table)和MMU(内存管理单元)将虚拟地址映射到物理地址。这种机制提供了内存保护、地址空间隔离和高效的内存管理。
虚拟地址空间
栈区 (Stack)
堆区 (Heap)
代码段 (Text)
数据段 (Data)
MMU
物理内存
Frame 1
Frame 2
Frame 3
Frame 4
页表结构详解
页表是内存映射的核心数据结构,它记录了虚拟页面到物理页面的映射关系以及相关的权限信息。
页表项 (Page Table Entry) 示例:
虚拟地址
物理地址
权限
标志位
0x7fff1234
0x1a2b3000
RW-
Present, User, Writable
0x7f8b4567
0x2c4d5000
RWX
Present, User, Executable
0x55555554
0x3e6f7000
R-X
Present, User, Execute-only
0x55555558
0x4a8b9000
RW-
Present, User, Dirty
1. 地址分解 虚拟地址分解为页号和偏移量
2. 页表查找 通过页号查找页表项
3. 权限检查 验证访问权限和有效性
4. 地址转换 组合物理页号和偏移量
匿名映射 (Anonymous Mapping)
匿名映射不与任何文件关联,主要用于分配堆内存、栈空间等。
// 分配8KB匿名内存
void *ptr = mmap(
NULL, // 让内核选择地址
8192, // 大小: 8KB
PROT_READ | PROT_WRITE, // 可读写
MAP_PRIVATE | MAP_ANONYMOUS, // 私有匿名
-1, // 无文件描述符
0 // 无偏移量
);
堆内存分配
malloc()内部使用匿名映射分配大块内存
栈空间扩展
当栈空间不足时自动扩展
文件映射 (File Mapping)
将文件内容直接映射到虚拟地址空间,实现文件的内存访问。
// 将文件映射到内存
int fd = open("data.txt", O_RDWR);
struct stat sb;
fstat(fd, &sb);
char *file_data = mmap(
NULL, // 地址由内核选择
sb.st_size, // 文件大小
PROT_READ | PROT_WRITE, // 读写权限
MAP_SHARED, // 共享映射
fd, // 文件描述符
0 // 从文件开头映射
);
高效文件IO
避免read/write系统调用开销
延迟加载
按需从磁盘加载文件内容
共享映射 (Shared Mapping)
多个进程可以共享同一块物理内存区域,实现进程间通信。
// 创建共享内存段
int shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, 4096);
void *shared_mem = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED, // 关键:共享映射
shm_fd,
);
进程间通信
高效的IPC机制
内存共享
多个进程共享同一物理页面
私有映射 (Private Mapping)
采用写时复制(COW)机制,每个进程拥有独立的内存副本。
// 私有文件映射
void *private_data = mmap(
NULL,