K02 — Process Address Space: Virtual Address Management and VMA
Key Insight: Each process’s address space is an independent map. Every region on the map is described by a VMA.
What is a VMA (Virtual Memory Area)
VMA (Virtual Memory Area) is a Linux kernel data structure describing a contiguous region in a process’s virtual address space.
VMA 的定义:
struct vm_area_struct {
struct mm_struct *vm_mm; // 所属进程
unsigned long vm_start; // 起始地址(包含)
unsigned long vm_end; // 结束地址(不包含)
pgprot_t vm_page_prot; // 页面保护(r/w/x)
unsigned long vm_flags; // 标志位(VM_READ/VM_WRITE/VM_EXEC等)
struct file *vm_file; // 如果是文件映射,记录文件
unsigned long vm_pgoff; // 文件内的页偏移
struct vm_operations_struct *vm_ops; // 操作函数指针
unsigned long vm_private_data; // 私有数据
};
一个典型的进程地址空间包含多个 VMA:
0x0000000000400000 ~ 0x0000000000401000 : r-xp (代码段,elf)
0x0000000000600000 ~ 0x0000000000601000 : rw-p (数据段)
0x00007f0000000000 ~ 0x00007f0000200000 : rw-p [heap] (堆)
0x00007fffc8c00000 ~ 0x00007fffc8c20000 : rw-p [stack] (栈)VMA Flags (vm_flags)
关键 vm_flags:
VM_READ / VM_WRITE / VM_EXEC:
- 页面的读写执行权限
- 影响 PTE 中的 protection 位
VM_SHARED / VM_PRIVATE:
- SHARED:映射对所有进程可见(文件映射 / 共享内存)
- PRIVATE:写时复制(fork 后的 COW)
VM_GROWSDOWN:
- 栈区域,栈可以向下扩展(glibc 的动态栈扩展)
VM_IO:
- 设备 I/O 区域(ioremap)
VM_MAYREAD / VM_MAYWRITE / VM_MAYEXEC:
- 权限上限(允许设置的权限上限)
- 即使 vm_flags 中没有 READ,但如果 MAYREAD=1,可以通过 mprotect 添加
VM_DENYWRITE:
- 拒绝写入(映射文件时设置)Relationship Between mmap and VMA
mmap 系统调用的作用:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
1. 创建新的 VMA
- 内核分配一个新的 VMA 结构
- 设置 vm_start ~ vm_end(基于 addr, length, flags)
- 设置 vm_flags(基于 prot, flags)
2. 建立地址映射
- 如果是文件映射(MAP_FILE):vm_file = fd 对应的 file
- 如果是匿名映射(MAP_ANON):vm_file = NULL
- 物理页面按需分配(demand paging)
3. 返回起始地址
- 内核返回 vm_start 给用户程序
例子:
mmap(NULL, 4096, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
→ 创建匿名私有映射
→ VMA: vm_start=0x7f..., vm_end=vm_start+4096
→ vm_flags: VM_READ|VM_WRITE|VM_PRIVATE
→ vm_file: NULLVMA 链表和红黑树:
Linux 中每个进程的 mm_struct 维护 VMA:
struct mm_struct {
struct vm_area_struct *mmap; // VMA 链表(按地址排序)
struct rb_root mm_rb; // VMA 红黑树(O(log n) 查找)
unsigned long mmap_base; // mmap 基址
unsigned long start_code, end_code; // 代码段范围
unsigned long start_data, end_data; // 数据段范围
unsigned long start_brk, brk; // 堆范围
unsigned long start_stack; // 栈顶
};
查找:
- 快速查找(给定地址):从红黑树 O(log n)
- 遍历所有 VMA:从链表(用于 proc 映射读取)brk and Heap Management
进程的堆(Heap):
堆的起始地址 = start_brk
堆的结束地址 = brk
程序启动时(C runtime):
- start_brk = end_data(数据段结束)
- brk = start_brk
malloc 底层:
- < 128KB:brk() 扩展堆(调用 sbrk)
- >= 128KB:mmap() 匿名映射(更灵活)
brk 系统调用:
int brk(void *addr);
- 设置 brk = addr
- 如果 addr > old brk:分配新的 VMA 或扩展现有 VMA
- 如果 addr < old brk:收缩 VMA,释放页面
sbrk 系统调用:
void *sbrk(int increment);
- brk = brk + increment
- 返回 old brk
- glibc malloc 用 sbrk 实现小对象分配
堆的 VMA:
0x0000000000600000 ~ 0x0000000000601000
↕
start_brk brk
VMA: rw-p, [heap]Automatic Stack Expansion
栈的 VMA 特点:
栈 VMA 有特殊标志 VM_GROWSDOWN:
- 允许栈向下扩展(向低地址)
- 访问页面不在 VMA 内时,触发 page fault
栈扩展流程:
程序访问 0x00007fffc8c0f000(栈)
→ 不在任何 VMA 内
→ 找到相邻的 VMA(栈)vm_flags & VM_GROWSDOWN
→ 检查扩展是否合法(不超过 RLIMIT_STACK)
→ 扩展 VMA:vm_start -= PAGE_SIZE
→ 分配物理页面,建立页表映射
→ 返回
RLIMIT_STACK 控制栈的最大大小:
$ ulimit -s // 查看当前限制(KB)
$ ulimit -s 8192 // 设置为 8MB/proc/self/maps Explained
查看进程地址空间:
$ cat /proc/self/maps
00400000-00404000 r-xp /bin/cat ← 代码段(可执行,私有)
00600000-00601000 rw-p 00000000 00:00 0 ← 数据段(读写,私有)
7ffd8c000000-7ffd8c020000 rw-p 00000000 00:00 0 ← 堆(匿名,私有,可读写)
7ffd8c020000-7ffd8c0a0000 ---p 00000000 00:00 0 ← 保护页(guard page,无权限)
7fffc8c00000-7fffc8c02000 rw-p [stack] ← 栈(可读写,私有)
ffff8800000000-ffff8880000000 r-xp 00000000 00:00 0 [vsyscall] ← vsyscall(64-bit)
格式:
start-end rwx p offset major:minor inode pathname
字段解释:
start ~ end:VMA 地址范围
rwx:vm_flags(r=读, w=写, x=执行, p=private, s=shared)
offset:文件映射的偏移
major:minor:设备号(文件映射)
inode:文件的 inode(文件映射)
pathname:映射的文件或匿名区域
匿名映射:[heap], [stack], [vsyscall], [vdso], [vvar]Summary
- VMA: Virtual Memory Area; data structure describing a contiguous region in a process’s virtual address space
- vm_flags: VM_READ, VM_WRITE, VM_EXEC, VM_SHARED, VM_PRIVATE, VM_GROWSDOWN, etc.
- mmap: Creates VMA; establishes mapping from virtual address to file or anonymous region
- VMA Management: Linked list (iteration) + red-black tree (fast lookup)
- Heap (brk): start_brk to brk; sbrk/brk system calls; small objects use brk; large objects use mmap
- Stack: VM_GROWSDOWN flag; auto-expands on access beyond limit; bounded by RLIMIT_STACK
Next (K03): After fork, how is the address space copied to the child process? copy_page_range, COW, and special vfork handling.
Comments