1. 程序地址空间回顾C语言阶段学习过程序地址空间长这样代码段数据段这些是常量区栈区堆区还有一些系统需要的空间这些是内存吗 ——不是内存。这些都是虚拟地址空间OS给我们画的大饼整齐排列的虚拟地址 - 通过页表映射物理地址 - 存放在零散的物理内存中实际上的物理内存中不存在那么多分区各种数据都是零散存放的虚拟地址的意义之一就是管理内存碎片2. 通过C代码展示虚拟地址排布感受虚拟内存#include stdio.h #include unistd.h #include stdlib.h int g_unval; int g_val 100; int main(int argc, char *argv[], char *env[]) { const char *str helloworld; printf(code addr: %p\n, main); printf(init global addr: %p\n, g_val); printf(uninit global addr: %p\n, g_unval); static int test 10; char *heap_mem (char*)malloc(10); char *heap_mem1 (char*)malloc(10); char *heap_mem2 (char*)malloc(10); char *heap_mem3 (char*)malloc(10); printf(heap addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(test static addr: %p\n, test); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(read only string addr: %p\n, str); for(int i 0 ; i argc; i) { printf(argv[%d]: %p\n, i, argv[i]); } for(int i 0; env[i]; i) { printf(env[%d]: %p\n, i, env[i]); } return 0; }通过打印对应变量的地址感受每种变量在内存的排布3. 一个id两个值地址相同 - 虚拟地址地址一样但是两个值绝对不是物理地址。而是虚拟地址空间4. 虚拟地址空间详细图解一、进程虚拟内存空间划分从代码到地址布局代码与数据地址观测通过打印变量地址如全局变量、堆、栈、常量等可观察到代码段code addr、初始化全局init global、未初始化全局unit global地址接近属于代码/数据区。堆heap addr地址递增符合“堆向上生长”栈stack addr地址递减符合“栈向下生长”。命令行参数argv、环境变量env位于栈附近属于栈区附属区域。虚拟地址空间的本质程序运行即进程进程存在则虚拟地址空间必然存在。OS 通过规划虚拟地址空间而非直接操作物理内存将代码、数据、堆、栈等分区管理再映射到物理内存。二、页表与地址转换MMU 的角色页表的作用虚拟地址 → 物理地址的转换由MMU内存管理单元CPU 内置硬件 完成。页表存储虚拟地址到物理地址的映射关系CPU 只负责读取虚拟地址交给 MMU 转换过程对软件透明。页表的细节惰性分配进程malloc时仅分配虚拟地址空间物理内存延迟到“读/写”时才会创建映射避免空占物理内存。权限标志如r/w/x页表项标记内存区域的权限只读、可写、可执行若违规操作如写只读页内核会终止进程。三、虚拟地址空间的意义为何需要虚拟内存管理内存碎片虚拟地址将零散的物理内存“拼接”成连续的地址空间便于统一管理。保护内存安全进程仅操作虚拟地址内核通过页表隔离不同进程的内存防止越权访问。解耦进程与内存模块进程关心虚拟地址内核关心页表映射降低模块耦合。支持大内存与并发通过“惰性分配 swap 扩展”进程可使用远超物理内存的虚拟空间提升并发能力。四、VMA虚拟内存区域与 mm_struct内存描述符mm_struct进程的“虚拟地址空间总控”每个进程对应一个mm_struct记录虚拟地址空间的全局信息如代码段、数据段、堆、栈的起始/结束地址总内存大小等。VMA虚拟地址的“分段管理器”堆、栈反复创建销毁会导致虚拟地址空间“零散”mm_struct的简单start/end无法表示所有碎片。因此引入vm_area_structVMA每个 VMA 描述一段连续的虚拟内存区域含权限、起始/结束地址。多个 VMA 通过链表mmap串联覆盖所有零散空间。VMA 回指 mm_structvm_mm的意义VMA 通过vm_mm指针回指所属进程的mm_struct让局部内存区域能反向定位全局上下文如缺页异常时通过 VMA→mm_struct 找到页表修复映射。五、写时拷贝COW与进程创建子进程通过fork创建时默认共享父进程的物理内存浅拷贝仅复制页表。若父子进程尝试“写”操作触发写时拷贝内核为写操作分配新物理内存复制数据后修改页表保证进程间内存独立。六、虚拟内存空间的最终框架结构关系进程控制块task_struct→ 包含mm_struct虚拟地址空间总控→mm_struct包含vm_area_structVMA 链表。各 VMA 对应虚拟地址空间的不同区域代码、数据、堆、栈、文件映射等通过vm_mm关联mm_struct形成“进程-虚拟空间-物理内存”的完整映射链。