目录

Linux-虚拟进程地址空间

Linux —— 虚拟进程地址空间

https://i-blog.csdnimg.cn/direct/fbb63a4c43e048c68e21997cac2d5f34.gif#pic_center


🎁个人主页:

🔍系列专栏:

🌟心中的天空之城,终会照亮我前方的路

🎉欢迎大家点赞👍评论📝收藏⭐文章


虚拟进程地址空间

虚拟地址空间 是指一个 OS为每个运行中的进程(程序)提供的一个抽象的、独立的、连续的逻辑地址范围。这个空间是 “虚拟的”,这并不意味着物理内存中真的有这么一大块连续的区域,而是通过硬件(MMU,内存管理单元)和 Kernel 的协作,将虚拟地址映射到分散的物理内存页上

https://i-blog.csdnimg.cn/direct/513abce911df47b9bc98a500a1cb7d34.png


一、虚拟地址空间经典布局

一个进程的典型内存地址空间布局如下图所示,它被划分为多个具有不同权限(读、写、执行)的段(Segments):

从高地址到低地址:

  1. 内核空间(Kernel Space)
    • 通常位于地址空间的最高处(例如,在32位Linux中,0x C000 0000以上)。
    • 存放操作系统内核的代码、数据和数据结构。
    • 所有进程共享同一份内核映射。但这段空间受保护,用户态进程无法直接访问,必须通过系统调用(Syscall)进入内核态才能访问。
  2. (Stack)
    • 向下增长(向低地址方向)。
    • 用于存储局部变量函数参数返回地址等。
    • 每个函数被调用时,会在栈上分配一个新的“栈帧”。
    • 它的增长是自动的,但大小有限(通常默认为几MB),溢出会导致“栈溢出”错误。
  3. 内存映射段(Memory Mapping Segment)
    • 用于映射文件或匿名内存。
    • 动态链接库(如 .so.dll 文件)就加载在这里。
    • 也可以通过 mmap() 系统调用创建,用于大块内存的分配或进程间共享内存。
  4. (Heap)
    • 向上增长(向高地址方向)。
    • 用于动态内存分配。当程序员使用 malloc()new 等申请内存时,内存就从这里分配。
    • 堆的大小只受限于系统可用的虚拟内存总量,管理由程序员负责(分配和释放), improper management leads to memory leaks.
  5. BSS 段(.bss)
    • 存放未初始化的全局变量和静态变量
    • 在程序开始执行前,操作系统会将此段初始化为零。
  6. 数据段(.data)
    • 存放已初始化的全局变量和静态变量
  7. 代码段(文本段)(.text)
    • 存放程序的执行代码(机器指令)。
    • 通常是只读和可执行的,以防止代码被意外修改。
  8. 保留区(Reserved)
    • 通常是最低地址的一段空间(例如 0x00x400000),不允许访问,用于捕捉空指针等错误。

地址区域分布:

https://i-blog.csdnimg.cn/direct/af6c5f88b2d344d8b4a8e2647fcbd7d6.png


https://i-blog.csdnimg.cn/direct/5df83152f6f54baeae5650c0ad02fb16.png


感受虚拟地址:

fork():一次调用,两次返回

这是理解 fork() 最关键也是最反直觉的一点:

  • 在父进程中,fork() 返回新创建子进程的进程ID(PID)(一个大于0的数)。
  • 在子进程中,fork() 返回 0
  • 如果创建失败(例如系统资源不足),fork() 返回 -1

https://i-blog.csdnimg.cn/direct/c8f5692138b64793986dc5023a2c5ebd.png


进程具有独立性:数据层面上,互不影响;此时就需写时拷贝,实现进程的个性化

https://i-blog.csdnimg.cn/direct/7dae86ccf38c4f37aec58f791004c2dd.png

相同地址,获取不同变量值


二、页表

2.1 核心定义:什么是页表?

页表是虚拟内存系统的核心数据结构,是连接 虚拟地址物理地址 的“地图”或“翻译官”;是 Kernel 为每个进程维护的一个映射表,它记录了该进程的虚拟内存页对应到物理内存帧映射关系

简单来说,它的工作就是回答这个问题:

“这个进程看到的虚拟地址 X,实际上在物理内存的哪个地方?”


https://i-blog.csdnimg.cn/direct/707c0a5d87894cdda084d527ae8205e8.png


https://i-blog.csdnimg.cn/direct/6fa7db7e3b784798b73761a9a7a77226.png


https://i-blog.csdnimg.cn/direct/bc4204b19a0643cf9e6b85f29b8d479f.png


https://i-blog.csdnimg.cn/direct/3db4da1d3b954e62b78feaa2d66931aa.png


https://i-blog.csdnimg.cn/direct/b8555339290249be89af106d242dda92.png

OS 会将进程物理地址隐藏起来,我们只能观测到进程的虚拟地址


解决历史遗留问题:

https://i-blog.csdnimg.cn/direct/d9ff89e37180438c80daa0b463259777.png


2.2 为什么需要页表?

页表是实现虚拟地址空间这一抽象概念的技术基础。没有页表,虚拟内存就无法工作。它的存在是为了:

  1. 实现地址翻译:将程序使用的 虚拟地址转换 为硬件使用的 物理地址
  2. 实施内存保护:通过页表项中的权限位,控制进程对内存的访问(可读?可写?可执行?)。
  3. 支持“换出”到磁盘:通过页表项中的“存在/不存在”位,操作系统可以知道某页是否在物理内存中,如果不在,它的数据存放在硬盘的哪个位置。

三、虚拟地址空间

3.1 虚拟地址空间是什么?

  • **虚拟地址空间本质上就是 OS 给进程画的一张饼! **《大富翁例子》 让进程误以为其独占整个内存的相关资源

画大饼的作用:让每一个进程都认为自己有 4GB的物理内存空间,或者:让每一个进程都认为自己在独占物理内存空间

OS 为每个进程都画了大饼,所以我们也要把这张大饼管理起来


3.2 如何管理虚拟地址空间?

先描述,在组织!

将所有的 虚拟进程地址空间[饼],用链表的方式管理起来;因此,对饼的管理就转化为了对链表的增删查改

虚拟地址空间本质:Kernel当中为进程创建的结构体对象!

https://i-blog.csdnimg.cn/direct/4b38522aa4af41e7935371ff240e511b.png


https://i-blog.csdnimg.cn/direct/d56784f8cc8e44218fa64aefb68f65cc.png


https://i-blog.csdnimg.cn/direct/de305b9301b64fb19201fd67ffc27341.png

https://i-blog.csdnimg.cn/direct/e3eab7a20afe40a1a5e2979c19214346.png


3.3 为什么要有虚拟地址空间?

1. 将无/乱序的物理地址转变为有序的虚拟地址!

  • 对用户(进程)而言:虚拟地址空间是连续且有序的
  • 对系统(操作系统)而言:物理内存[完全随机且不连续]的分配是灵活且混乱的

https://i-blog.csdnimg.cn/direct/2de435ab6c3c47a5bc4dbbc2666f91e0.png


2. 地址转化过程中对地址与操作进行合法性判定,进而保护物理内存!

https://i-blog.csdnimg.cn/direct/67bf0a3545954ca487571d220b02de75.png


a. 什么是野指针?

https://i-blog.csdnimg.cn/direct/7164c38ca75a419ca30da1ab559061b1.png


b. char* str = “hello linux!”; *str = ‘H’;为什么在字符常量区写入就会崩溃?

https://i-blog.csdnimg.cn/direct/dcaa0484a6f74c1cabe32fe44d640af7.png


https://i-blog.csdnimg.cn/direct/36e8e0849873465e905d29e2a31b7113.png


3. 缺页中断 与 按需调页

缺页中断是操作系统 “欺骗” 进程的基础,也是它管理内存的得力工具(画大饼)

https://i-blog.csdnimg.cn/direct/1bc99f31adb24d68aa1a1a4cb5177c7b.png


4. 使进程管理与内存管理,进行一定程度的解耦合

https://i-blog.csdnimg.cn/direct/b27549e5feec42329eeab3dfa50480f1.png


https://i-blog.csdnimg.cn/direct/03a71d5e57f0420982814a602966c101.png

进程管理 & 内存管理 –——> 直线脱钩


四、工业疑问

a. 创建进程时,是否可以只创建 PCB/地址空间/页表?

核心观点:惰性加载 (Lazy Loading) 与按需调页 (Demand Paging)

问题背后隐藏着一个关键思想:为什么要在进程一开始就把它可能永远用不到的东西全部加载好呢? 这太浪费了….它们遵循 “惰性”原则,只在真正需要时才分配资源。这个过程就是通过 **缺页中断 ** 来实现的


https://i-blog.csdnimg.cn/direct/655630d0ff5144b38679d2aaddee2577.png


https://i-blog.csdnimg.cn/direct/0685742aa5ef4caa9fa646c8e6b43742.png


b. 创建进程现有task_struct,还是先加载数据/代码

一定先有管理结构task_structmm_struct,空页表[虚物]。滞后加载代码和数据[实物],发生在第一次访问时,由缺页中断机制驱动。并且,加载过程本身也是由这些数据结构指导

https://i-blog.csdnimg.cn/direct/fcc31c9625e8470282c0d4c6ce95213d.png


c. 如何理解进程挂起?

https://i-blog.csdnimg.cn/direct/1c56f32bf7b840ac94818f2eb3c31e7c.png


https://i-blog.csdnimg.cn/direct/ca15293e6e574726ab986df6a01b017e.png


https://i-blog.csdnimg.cn/direct/e3b2f0bff3c9485f88ccb979130b4c14.png


https://i-blog.csdnimg.cn/direct/c65fe2b1247b4fa5afeb6504835f17c2.png


https://i-blog.csdnimg.cn/direct/3927c3577a8a4c07b0885baee30a553f.png


五、虚拟内存管理

虚拟内存管理是一种内存抽象机制。虚拟内存管理系统的任务,就是将进程使用的这些虚拟地址(Virtual Address)动态地映射到物理内存上的物理地址(Physical Address),或者必要时映射到磁盘上的交换空间(Swap Space)

这个过程主要由计算机的 内存管理单元(MMU) 和操作系统内核共同完成。


描述 Linux 下进程的地址空间的所有的信息的结构体是 mm_struct (内存描述符)。每个进程只有⼀ 个 mm_struct结构,在每个进程的 task_struct结构中,有⼀个指向该进程的结构

https://i-blog.csdnimg.cn/direct/a1e99dbf0d534681b4d796b7f487a434.png

struct mm_struct
 {
	/*...*/
	struct vm_area_struct *mmap; /* 指向虚拟区间(VMA)链表 */        
	struct rb_root mm_rb; /* red_black树 */                
	unsigned long task_size; /*具有该结构体的进程的虚拟地址空间的⼤⼩*/             
/*...*/
 // 代码段、数据段、堆栈段、参数段及环境段的起始和结束地址。

    unsigned long start_code, end_code, start_data, end_data;
	unsigned long start_brk, brk, start_stack;
	unsigned long arg_start, arg_end, env_start, env_end;
 /*...*/

  • Virtual Memory

https://i-blog.csdnimg.cn/direct/a2afda78a58c46b08efaed6d64bb255b.png


https://i-blog.csdnimg.cn/direct/8f3e1c2b0add4092b5c35f120a53ac23.png


进程具有独立性:

  1. 内核数据结构独立!
  2. 加载进内存的代码和数据独立!

https://i-blog.csdnimg.cn/direct/c0601f669862400093cfb486615589e4.png


目前,我们对于虚拟地址空间的理解只能做到局部性的逻辑自洽


🌟 各位看官好我是

🌈 愿各位心中所想,终有所致!
https://i-blog.csdnimg.cn/direct/793fde0032ab48fb8073895672728ab6.gif#pic_center