一、核心概念

  • 虚拟地址:在Linux下,C/C++语言中所看到的地址(如变量地址、函数地址)全部是虚拟地址,而非物理内存地址。
  • 物理地址:用户进程无法直接看到或操作,由操作系统统一管理,并通过页表将虚拟地址映射到物理地址。
  • 进程地址空间:每个进程拥有自己独立的虚拟地址空间,由内核数据结构 mm_struct 完整描述。

二、进程地址空间的布局(32位平台典型布局)

  • 内核空间(1GB,高地址)
  • 用户空间(3GB,低地址),从高地址到低地址依次为:
    • 命令行参数与环境变量
    • 栈区(向下生长)
    • 共享区(动态库等)
    • 堆区(向上生长)
    • 未初始化数据段(BSS)
    • 初始化数据段(数据段)
    • 正文代码段(代码段)

该布局可通过代码打印各区域地址进行验证,地址值均为虚拟地址。


三、虚拟地址与父子进程的经典现象

  • 现象:fork创建子进程后,父子进程打印同一个全局变量的地址相同,但值不同
  • 结论
    • 地址相同说明是虚拟地址相同
    • 值不同说明它们映射到了不同的物理地址
    • 证明了父子进程拥有独立的地址空间,且采用写时拷贝技术。

四、内核数据结构:mm_structvm_area_struct

  • mm_struct:每个进程的 task_struct 中有一个指向 mm_struct 的指针,用于描述该进程的完整虚拟地址空间。
    • 包含字段:代码段、数据段、堆、栈、参数段、环境段的起始与结束地址。
  • vm_area_struct:用于描述一个独立的虚拟内存区域(VMA),如堆、栈、共享库等。
    • 组织方式:
      • 链表(mmap)适用于VMA数量较少时;
      • 红黑树(mm_rb)适用于VMA数量较多时,提高查找效率。

五、为什么要引入虚拟地址空间(解决的问题)

问题 说明
安全风险 若直接操作物理内存,任意进程可访问系统内存,易被恶意程序破坏。
地址不确定 程序每次加载到物理内存的位置不固定,导致编译时无法确定绝对地址。
效率低下 若以整个进程为单位进行内存交换(swap),开销大、效率低。

六、虚拟地址空间 + 分页机制带来的好处

  1. 内存保护

    • 所有地址访问必须经过OS的页表映射,OS可控制访问权限,保护内核及其他进程数据。
  2. 解耦合

    • 进程管理与内存管理分离,物理内存可任意位置加载进程数据,不影响进程自身视角。
  3. 延迟分配(按需分配)

    • malloc/new 只在虚拟地址空间申请内存,物理内存可暂不分配;
    • 真正访问时才触发缺页中断,由OS分配物理内存并建立映射(用户和进程无感知)。
  4. 进程独立性

    • 每个进程拥有独立的虚拟地址空间,互不干扰,增强了系统稳定性和安全性。

七、总结一句话

进程地址空间是操作系统为每个进程提供的独立虚拟内存视图,通过页表映射到物理内存,实现了内存保护、按需分配、进程隔离和高效管理,是现代操作系统稳定与安全的基础机制。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐