1. 进程,线程和协程
(1)进程
(2)线程
(3)协程
2. 进程间的切换
每个进程都以为自己拥有一整块独立的内存(例如从地址 0x00000000 开始),但实际上,这是一种由操作系统和硬件通过虚拟内存机制(Paging) 提供的“假象”。
- 每个进程都有属于自己的 页表(Page Table);
- 这些页表记录了该进程的 虚拟地址 ↔ 物理地址 映射关系;
- 所以在切换进程时,需要将当前正在使用的页表切换成新进程的页表。
(1)进程切换的步骤
第一步:保存当前进程的上下文(A进程)
- 保存当前的CPU 寄存器(通用寄存器、栈指针、程序计数器PC等)。
- 保存当前的页表基地址(例如
CR3寄存器的值)。 - 保存其他内核状态(如文件描述符、信号状态等)。
- 将这些信息存入进程控制块 PCB(Process Control Block)。
第二步:加载新进程的上下文(B进程)
- 可能会触发TLB Flush(清空地址转换缓存),防止旧页表污染。
- 加载B进程的寄存器、PC等状态。
- 设置新的页表基地址(例如设置
CR3为 B 进程的页表地址); 这一步是切换虚拟地址空间的关键。 - 加载B进程的内核栈指针、内核上下文。
(2)如何进行页表切换?
操作系统通过写入 CPU 中的一个特殊寄存器(例如 x86 上的 CR3 寄存器)来更换页表。
CR3寄存器保存当前页目录表(或多级页表的根)的物理地址。
举例:
- 进程 A 的页表根在物理地址
0x123000; - 进程 B 的页表根在物理地址
0x456000;
切换进程时,使用指令:
mov cr3, 0x456000 ; 让 CPU 使用进程 B 的页表
此时,再从虚拟地址访问内存时,所有的地址映射都变了,进入了进程 B 的“视角”。
(3)TLB Flush是什么?
TLB(Translation Lookaside Buffer)是一个缓存,保存最近访问过的虚拟地址 ↔ 物理地址 映射。
由于每个进程的虚拟地址空间不同,所以页表不同,在进程切换时必须清空 TLB,否则会导致旧进程的地址映射被误用。
这叫做 TLB flush,它是进程切换的一部分,会稍微影响性能。
3. 内存空间
内存空间是计算机系统中可用于存放数据和指令的一段地址范围,它由地址编号构成,可以映射到实际的存储设备(如物理内存或虚拟内存)。
内存空间 = 地址范围 = 一块逻辑上可访问的连续地址集合
(1)物理内存空间
定义:物理内存空间是实际硬件内存(RAM)中可以寻址的地址范围。
特点:
- 所有程序最终的数据和指令必须落地到物理内存中;
- 操作系统负责将虚拟地址翻译成物理地址;
- 物理内存中包括:用户程序数据、内核代码和数据、缓存、页表等;
- 访问物理内存必须经过操作系统控制(用户进程不能直接访问)。
(2)虚拟内存空间
定义:
虚拟内存空间是进程视角下的地址空间,由操作系统通过地址映射机制虚拟出来的一大片连续地址区。
每个进程都以为自己独占一整块地址空间(如 4GB 或更多),但这些地址其实不直接对应物理内存,而是通过页表映射的(虚拟地址 → 物理地址)。
特点:
- 操作系统会给每个运行中的进程提供一个独立的虚拟内存空间,这个空间可能比实际物理内存还大(如 4GB 或 128TB)。
- 相同的虚拟地址,在不同进程中可能指向完全不同的物理内存。
- 使用 MMU(内存管理单元)+ 页表 来实现地址映射。
- 支持地址隔离、内存保护、按需加载、共享内存等高级特性。
- 进程只看到自己的“虚拟地址空间”,彼此隔离。
- 使用虚拟内存空间可以提高安全性、可靠性和内存利用率。
一个典型用户进程的虚拟地址空间(从低到高):
虚拟地址空间布局:
+--------------------------+ ← 高地址(0xFFFFFFFF)
| 内核空间(不可访问) |
+--------------------------+
| 用户栈 Stack |
+--------------------------+
| 动态链接库 mmap 区域 |
+--------------------------+
| 堆 Heap(动态分配) |
+--------------------------+
| BSS段(未初始化的全局变量) |
+--------------------------+
| 数据段(已初始化的全局变量)|
+--------------------------+
| 代码段 Text(程序指令) |
+--------------------------+ ← 低地址(0x00000000)
(3)内核内存空间(Kernel Space)
内核内存空间是虚拟地址空间中,专门为操作系统内核保留的一段地址区域,只有内核可以访问,普通用户进程无法进入。
(4)用户内存空间(User Space)
用户内存空间是进程可访问的虚拟地址空间范围,也叫用户态虚拟内存空间,用于存放用户程序的数据、代码和堆栈等。
这部分空间对进程是“可读写”的,但不能直接访问内核数据或控制硬件。
页
(1)页(Page)
页是操作系统管理内存的最小单位,操作系统将虚拟地址空间被划分成的固定大小的块(如4KB)。
- 一页的大小通常是 2 的整数次幂,例如 4KB、8KB、16KB(大多数现代操作系统使用 4KB)。
- 内存被划分为 一个个固定大小的块,这些块被称为“页”。
这样做的好处是简化内存分配和管理,使得内存不必以连续方式分配,从而减少碎片问题。
(2)虚拟页(Virtual Page)
虚拟页 是 进程看到的内存地址空间中的页。
当你写程序访问变量,比如 int a = 5;,你访问的是虚拟地址,不是物理内存的真实地址。
- 操作系统为每个进程维护一个虚拟地址空间,这个空间被划分成一页一页(即虚拟页)。
- 每个进程以为自己拥有独占的完整内存空间,其实只是操作系统提供的一个“假象”。
这就引出了另一个重要机制:地址映射。
(3)物理页(Physical Page)
物理页 是实际 RAM(主内存)中的页块。
- RAM(物理内存)也被划分成固定大小的块,与虚拟页一一对应,这些就是“物理页”。
- 虚拟页不会永远驻留在内存中,它们可以被置换(swap)到磁盘上(即“页面置换”机制)。
(4)页表(Page Table)
页表的概念?
页表就是一个查找表,记录了:
“虚拟页号对应的物理页框号“,以及一些状态标志位(控制权限)。
为什么要页表?
现代操作系统为每个进程提供了一个虚拟地址空间。
但是程序运行时必须访问实际的物理内存(RAM),因此操作系统需要一种机制来将虚拟地址 → 物理地址,这个机制就是页表。
页表是操作系统为每个进程维护的一个数据结构,用于记录:
每个虚拟页号(VPN: Virtual Page Number) 对应的是哪个物理页号(PPN: Physical Page Number)。
页表的特点:
- 每个进程有自己的页表;
- 页表中每个条目记录了某个虚拟页是否映射到了某个物理页;
- 如果该虚拟页没有在内存中,会触发“缺页异常(Page Fault)”,操作系统将它从磁盘调入物理内存。
各种地址的含义与关系
(1)物理地址(Physical Address)
定义:物理地址是RAM(内存)上的真实地址,它是CPU最终访问内存时用的地址。
- 只有内存控制器才能识别物理地址。
(2)逻辑地址(Logical Address)
定义:逻辑地址是程序代码中使用的地址,通常是[段选择子 + 段内偏移]。
- 逻辑地址在x86中等价于虚拟地址(32位时代)。
- 可以将其理解为程序员在代码中写的地址,如访问变量:
int a = 5; - 逻辑地址 = 段寄存器(如
cs,ds,ss)+ 偏移量
(3)虚拟地址(Virtual Address)
定义:虚拟地址是广义概念,指进程所见的地址空间。
- 在32位系统中,它与逻辑地址可以认为是一样的。
- 在64位系统中,不再使用段机制,虚拟地址等价于线性地址。
- 每个进程都有自己独立的虚拟地址空间。
- 所有程序运行时访问的地址,实际都是虚拟地址。
(4)线性地址(Linear Address)
定义:经过分段转换后的地址,但尚未分页的地址。
- 分段阶段之后、分页阶段之前的地址。
- 所有分页机制的输入地址就是线性地址。
- 在线性地址阶段:逻辑地址 → 段表 → 线性地址。
- 在分页阶段:线性地址 → 页表 → 物理地址。
(5)有效地址(Effective Address)
定义:用于寻址的段内偏移值(即偏移部分)。
- 通常由汇编指令中的寻址方式(如
[ebx + 4*eax + 0x20])计算得出。 - 有效地址 + 段基址 = 线性地址。
(6)总结
程序使用的是逻辑地址(或虚拟地址),它会被分段转换成线性地址,再由分页机制转换成物理地址,最终访问 RAM。

Leave a comment