1、进程虚拟空间的布局
如下图可以看清楚代码段在低地址;只读数据段、数据段、BSS段依次向上;堆区从低地址向高地址增长;栈区从高向低地址增长;命令行参数和环境变量位于栈的最顶端。



2、虚拟地址引入
虚拟地址是进程看到的"逻辑地址",操作系统通过页表和写时复制,让相同的虚拟地址对应不同的物理内存,从而实现了进程间的地址隔离和高效内存管理。
如下图:


从输出可以清晰看到:
- 子进程: child[30501]: 100 : 0x601058
- 父进程: parent[30500]: 0 : 0x601058
这里的核心现象是:
-
变量值不同:子进程里 g_val 是 100 ,父进程里 g_val 还是 0 。
-
变量地址相同:两者的变量地址都是 0x601058 。
通俗解释
-
地址相同:这个地址是虚拟地址,每个进程都有自己独立的虚拟地址空间,所以父子进程里同一个变量的虚拟地址可以完全一样。
-
值不同:子进程修改 g_val 时,操作系统触发了写时复制(COW),给子进程单独分配了一块物理内存,把修改后的值存在了新的物理页上。所以,虽然虚拟地址相同,但它们实际对应的物理内存已经是两块不同的区域,因此值互不影响。
虚拟地址总结
虚拟地址是进程自己看到的"门牌",操作系统通过页表把相同的"门牌"映射到了不同的"房间"(物理内存),所以值不一样。

- 刚 fork() 完
-
父子进程共用同一块物理内存
-
虚拟地址一样,物理地址也一样
- 子进程一修改数据
- 操作系统发现:有人要改共享内存
-立刻给子进程新开辟一块物理内存
- 把原来的数据复制过去
- 只修改子进程的页表,让它的虚拟地址指向这块新物理内存
- 结果
-
子进程改的是新物理内存
-
父进程还是用老物理内存
-
所以:子进程怎么改,都完全不影响父进程
最简总结:
虚拟地址没变 → 页表变了 → 物理内存换了
这就是:写时复制(COW)
虚拟地址空间概念

虚拟地址空间是OS给进程画的一张饼
OS对虚拟地址空间的管理
系统中有很多的进程,每个进程有自己的虚拟地址空间,所以OS要管理这些虚拟地址空间,
操作系统给每个进程"伪造"了一整片连续的地址空间,
这就叫虚拟地址空间。
每个进程的虚拟地址空间,
都由一个叫 struct mm_struct 的结构体来管理。
操作系统通过管理所有进程的 mm_struct ,
实现对所有虚拟地址空间的统一管理。
操作系统负责管理所有进程的虚拟地址空间。
- 每个用户进程:
→ 有一个 struct mm_struct
- 操作系统:
→ 通过管理一堆 mm_struct 来管理所有虚拟地址空间
如何理解虚拟地址空间中的区域划分?
我用最简单、最考试、最能记住的方式,只讲核心,你一下就懂:
虚拟地址空间的区域划分 ------ 一句话理解
就是把进程那块"假的虚拟地址",按用途分成好几块,每块干不同的事,互不干扰。
为什么要划分?
-
代码不能随便改
-
数据可以读写
-
函数调用要用栈
-
malloc 要用堆
如果不分区,全部混在一起,程序一跑就崩溃。
所以操作系统把虚拟地址空间分成不同区域,这就叫:区域划分
分成哪几个区?(只记最核心 4 个)
- 代码区
放程序代码,只读,不能改。
- 数据区
放全局变量、静态变量。
- 堆区(heap)
malloc 动态申请内存用,从下往上长。
- 栈区(stack)
局部变量、函数调用用,从上往下长。
总结:
虚拟地址空间是假的地址范围,
操作系统为了安全、好管理,
把它按功能分成不同区域,
这就叫 虚拟地址空间的区域划分。
1、什么是页表?
页表是操作系统维护的地址映射表,负责将进程的虚拟地址翻译成物理内存的真实地址,每个进程有独立的页表。
2. 查表工作谁来做?
主要由 CPU 内的 MMU(内存管理单元) 硬件完成。
发生页缺失时,由操作系统内核介入处理。
3. 为什么要有虚拟地址空间?
隔离保护:进程间互不干扰,提升系统稳定性。
简化编程:程序员无需关心物理内存细节。
高效利用:通过分页、共享、交换等技术,突破物理内存限制。
地址规整:提供连续的虚拟地址块,方便内存管理。
或:
-
控制进程的行为(拦截进程的非法行为),保护物理内存。
-
有了虚拟地址空间和页表,原则上:将进程的内存空间布局,无序变有序。
-
让进程管理和内存管理,解耦合
懒加载
在 Linux 进程创建和内存管理的语境下,懒加载(Lazy Loading / 延迟加载) 指的是:
进程创建时,操作系统不立即把代码和数据全部加载到物理内存,而是先创建好内核数据结构(如 task_struct 、 mm_struct 、页表等),建立好虚拟地址空间的映射关系。
当进程真正执行到某段代码、访问某个数据时,发现对应的页不在物理内存里,触发页错误(Page Fault),操作系统才会把那一页的内容从磁盘加载到内存,并更新页表。