WAYNETS.ORG

Game and Program

操作系统知识总结

作者:

发表于

Context Polling System Post-Processing Renderer

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。

Read Next:


Leave a comment