1.5 我是一个进程
把程序、地址空间、页表和线程放进同一个进程资源合同,验证装载、隔离、调度与回收。
学习目标
- 能解释进程如何用虚拟地址空间、页表和资源身份隔离一次程序执行
- 能沿程序的装载、地址映射、线程调度到退出回收追踪状态,并定位首个异常
- 能用正常、边界和单一故障样本复核地址、权限、共享映射和资源生命周期
1.5 我是一个进程
本页依据刘欣《码农翻身》(2018 年第 1 版)及出版社公开书目信息,独立重构 1.5 我是一个进程。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图、练习答案或代码。
程序不是磁盘上的一段静态字节。程序被装载并创建运行实例后,进程拥有虚拟地址空间、资源身份和生命周期;页表把虚拟页映射到物理页,线程则在该进程的资源合同内执行。这个模型可以解释地址重定位、分页、权限、调度、共享和退出回收之间的关系。
三个会让进程模型失真的陷阱
五个词组成进程资源合同
<Term def="进程看到的地址、代码、数据、堆、栈和映射关系;同一个数值在不同进程中不必指向同一物理页。">虚拟地址空间</Term>让隔离成为可观察对象。访问是否合法,取决于页表、权限和当前进程。
<Term def="把虚拟页号、权限和有效位转换为物理页位置的结构;它决定一次访问能否完成以及失败如何报告。">页表</Term>连接地址重定位和虚拟内存:分页改变映射,不等于改变指针的语义。
<Term def="让不同进程拥有独立地址与资源视图,并通过权限和显式共享边界控制跨进程访问。">进程隔离</Term>保护一个进程的错误不直接破坏另一个进程。共享不是默认行为,必须有映射和所有权。
<Term def="从程序装载、资源创建、线程运行、异常处理到退出回收的完整状态范围。">资源生命周期</Term>要求观察创建和清理两端;只看启动成功无法证明合同闭合。
<Term def="在某个进程地址空间和资源上下文中执行的调度单位,拥有自己的栈、状态和调度记录。">线程</Term>不是脱离进程的独立程序。线程切换必须保存上下文,退出必须说明资源归属。
五个词形成进程链:装载产生地址空间,页表建立映射,隔离限制权限,线程在上下文中运行,资源生命周期负责回收。任何一段缺证据,都不能把“程序启动了”当成完整成功。
目录节点到机制证据
批处理系统
批处理系统把一批作业交给系统按顺序或策略运行。它暴露出“程序文件”和“运行实例”的差异:系统必须为每个作业建立状态、资源边界和结果记录,而不是只把文件依次读进内存。
多道程序
多道程序让多个作业在系统中交替前进。它要求进程拥有可区分的地址空间和资源身份,调度一个作业时不能把另一个作业的页表、文件或权限带进来。
地址重定位
地址重定位把程序使用的地址转换为运行时可访问的地址。重定位不意味着“指针就是物理位置”;复核时要同时记录虚拟地址、页表项、权限和物理页。
分时系统
分时系统通过时间片和上下文切换让多个进程获得响应机会。切换必须保存寄存器、栈和地址空间上下文,否则下一线程会在错误的资源视图中运行。
分块装入内存
分块装入内存把程序的代码和数据按需要放入可用区域。边界样本要检查部分装载、缺页、权限和回收,不能因为入口代码已执行就宣布全部资源有效。
虚拟内存:分页
虚拟内存:分页把地址空间分成页,并用页表将虚拟页映射到物理页。访问未映射或权限不足的页,应在明确的异常点停止,而不是读到另一个进程的内容。
分段 分页
分段 分页可以同时表达逻辑段和固定大小页的约束。复核时分开记录段权限、页映射和偏移,避免把两个层次合成一个无法诊断的“地址”。
程序的装载
程序的装载建立进程初始地址空间、入口、栈、参数和依赖。装载成功只证明初始状态成立,还需要继续验证线程运行、异常和退出回收。
线程
线程共享进程的地址空间和部分资源,但拥有自己的栈、寄存器和调度状态。线程的故障要同时检查进程上下文、共享资源和生命周期所有者。
进程合同
type ProcessRun = {
processId: string;
virtualPages: string[];
pageTable: string[];
threads: string[];
resources: string[];
firstDeviation: string;
cleanup: string[];
decision: "run" | "pause" | "reclaim";
};
function canSchedule(run: ProcessRun) {
return (
run.processId.length > 0 &&
run.virtualPages.length > 0 &&
run.pageTable.length > 0 &&
run.threads.length > 0 &&
run.firstDeviation.length > 0
);
}这个合同不把进程简化成一个数字或一张进程表。它要求调度前能找到地址映射、线程上下文和资源所有者;发生异常时记录首差,退出时验证 cleanup,而不是只看退出码。
四步复核进程生命周期
1. 装载程序并建立地址空间
冻结程序文件、入口、参数、页大小和权限,记录程序的装载、初始虚拟页与页表。先预测第一次访问会命中哪一页以及缺页时的动作。
Interactive lab
选择进程样本,定位首个资源变化
输入
线程访问未映射页面,或共享区域的权限在边界样本中发生变化。
首个变化
页表权限先改变,访问应停止而不是落到其他物理页。
裁决动作
暂停访问,修正映射或显式建立共享合同。
先确认当前进程和页表,再解释线程访问;地址相同不代表物理资源相同。
正常、边界与单一故障证据
| 样本 | 只改变的变量 | 预期判定 | 必存证据 |
|---|---|---|---|
| 正常 | 映射、权限、线程和资源完整 | 访问可解释,退出能完整回收 | 页表、上下文、状态、清理记录 |
| 边界 | 页边界、权限、共享范围或资源容量越过阈值 | 在异常点停止并给出回退 | 阈值、虚拟地址、错误、替代路径 |
| 单一故障 | 一个页表项、线程、文件或回收动作失效 | 首个资源异常暴露并恢复 | 首差、所有者、回收和回归 |
最小进程证据包与反例
证据包包含程序哈希、进程身份、入口参数、虚拟页和页表、权限、物理页、线程上下文、文件与共享资源、调度轨迹、异常、退出码、回收记录和独立复核结果。最终输出正确或进程表消失,只能辅助定位,不能单独证明资源已经安全释放。
反例可以是两个进程的相同虚拟地址指向不同物理页,也可以是共享映射释放后仍有线程访问。发现反例后,保留地址和生命周期轨迹,缩小共享边界、修复权限或回收合同并重放;不要用“通常能运行”替代隔离证据。
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- 虚拟地址空间
进程看到的地址、代码、数据、堆、栈和映射关系。
- 页表
把虚拟页号、权限和有效位转换为物理页位置的结构。
- 进程隔离
让不同进程拥有独立地址与资源视图,并用权限和显式共享边界控制访问。
- 资源生命周期
从程序装载、资源创建、线程运行、异常处理到退出回收的完整状态范围。
- 线程
在某个进程地址空间和资源上下文中执行的调度单位。
练习
练习
问题 1: 两个进程都打印出虚拟地址 0x4000,是否说明它们访问同一块物理内存?
问题 2: 线程在进程退出后仍访问共享页面,应该先查哪一处?
问题 3: 一个程序能启动,但分页压力上升后出现错误。你会保存哪些证据?
本页小结
1.5 我是一个进程的关键不是把进程背成一张表,而是能从程序的装载、地址重定位、虚拟内存:分页、线程调度到退出回收追踪所有权和状态。用页表、权限、隔离和生命周期证据解释正常与边界,才能在故障时知道应该暂停、共享、回退还是回收。