1.5 我是一个进程

把程序、地址空间、页表和线程放进同一个进程资源合同,验证装载、隔离、调度与回收。

学习目标

  • 能解释进程如何用虚拟地址空间、页表和资源身份隔离一次程序执行
  • 能沿程序的装载、地址映射、线程调度到退出回收追踪状态,并定位首个异常
  • 能用正常、边界和单一故障样本复核地址、权限、共享映射和资源生命周期

1.5 我是一个进程

本页依据刘欣《码农翻身》(2018 年第 1 版)及出版社公开书目信息,独立重构 1.5 我是一个进程。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图、练习答案或代码。

程序不是磁盘上的一段静态字节。程序被装载并创建运行实例后,进程拥有虚拟地址空间、资源身份和生命周期;页表把虚拟页映射到物理页,线程则在该进程的资源合同内执行。这个模型可以解释地址重定位、分页、权限、调度、共享和退出回收之间的关系。

三个会让进程模型失真的陷阱

五个词组成进程资源合同

<Term def="进程看到的地址、代码、数据、堆、栈和映射关系;同一个数值在不同进程中不必指向同一物理页。">虚拟地址空间</Term>让隔离成为可观察对象。访问是否合法,取决于页表、权限和当前进程。

<Term def="把虚拟页号、权限和有效位转换为物理页位置的结构;它决定一次访问能否完成以及失败如何报告。">页表</Term>连接地址重定位和虚拟内存:分页改变映射,不等于改变指针的语义。

<Term def="让不同进程拥有独立地址与资源视图,并通过权限和显式共享边界控制跨进程访问。">进程隔离</Term>保护一个进程的错误不直接破坏另一个进程。共享不是默认行为,必须有映射和所有权。

<Term def="从程序装载、资源创建、线程运行、异常处理到退出回收的完整状态范围。">资源生命周期</Term>要求观察创建和清理两端;只看启动成功无法证明合同闭合。

<Term def="在某个进程地址空间和资源上下文中执行的调度单位,拥有自己的栈、状态和调度记录。">线程</Term>不是脱离进程的独立程序。线程切换必须保存上下文,退出必须说明资源归属。

五个词形成进程链:装载产生地址空间,页表建立映射,隔离限制权限,线程在上下文中运行,资源生命周期负责回收。任何一段缺证据,都不能把“程序启动了”当成完整成功。

进程生命周期:地址和资源一起被创建与回收程序文件只是输入,运行实例还要拥有映射、上下文、权限和清理1装载程序与入口已建立2映射页表与权限当前映射点3调度线程与上下文待验证4隔离资源与共享待验证5回收退出与清理待验证任何线程都不能越过所属进程的地址、权限和生命周期
专属图示:进程把地址映射、线程上下文和资源回收放进同一条生命周期。

目录节点到机制证据

批处理系统

批处理系统把一批作业交给系统按顺序或策略运行。它暴露出“程序文件”和“运行实例”的差异:系统必须为每个作业建立状态、资源边界和结果记录,而不是只把文件依次读进内存。

多道程序

多道程序让多个作业在系统中交替前进。它要求进程拥有可区分的地址空间和资源身份,调度一个作业时不能把另一个作业的页表、文件或权限带进来。

地址重定位

地址重定位把程序使用的地址转换为运行时可访问的地址。重定位不意味着“指针就是物理位置”;复核时要同时记录虚拟地址、页表项、权限和物理页。

分时系统

分时系统通过时间片和上下文切换让多个进程获得响应机会。切换必须保存寄存器、栈和地址空间上下文,否则下一线程会在错误的资源视图中运行。

分块装入内存

分块装入内存把程序的代码和数据按需要放入可用区域。边界样本要检查部分装载、缺页、权限和回收,不能因为入口代码已执行就宣布全部资源有效。

虚拟内存:分页

虚拟内存:分页把地址空间分成页,并用页表将虚拟页映射到物理页。访问未映射或权限不足的页,应在明确的异常点停止,而不是读到另一个进程的内容。

分段 分页

分段 分页可以同时表达逻辑段和固定大小页的约束。复核时分开记录段权限、页映射和偏移,避免把两个层次合成一个无法诊断的“地址”。

程序的装载

程序的装载建立进程初始地址空间、入口、栈、参数和依赖。装载成功只证明初始状态成立,还需要继续验证线程运行、异常和退出回收。

线程

线程共享进程的地址空间和部分资源,但拥有自己的栈、寄存器和调度状态。线程的故障要同时检查进程上下文、共享资源和生命周期所有者。

进程合同

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 / 4

1. 装载程序并建立地址空间

冻结程序文件、入口、参数、页大小和权限,记录程序的装载、初始虚拟页与页表。先预测第一次访问会命中哪一页以及缺页时的动作。

进程生命周期:地址和资源一起被创建与回收程序文件只是输入,运行实例还要拥有映射、上下文、权限和清理1装载程序与入口已建立2映射页表与权限当前映射点3调度线程与上下文待验证4隔离资源与共享待验证5回收退出与清理待验证任何线程都不能越过所属进程的地址、权限和生命周期
专属图示:进程把地址映射、线程上下文和资源回收放进同一条生命周期。

Interactive lab

选择进程样本,定位首个资源变化

权限边界

输入

线程访问未映射页面,或共享区域的权限在边界样本中发生变化。

首个变化

页表权限先改变,访问应停止而不是落到其他物理页。

裁决动作

暂停访问,修正映射或显式建立共享合同。

先确认当前进程和页表,再解释线程访问;地址相同不代表物理资源相同。

正常、边界与单一故障证据

进程证据矩阵:看第一处资源异常正常样本看隔离,边界样本看权限,故障样本看回收观察项正常边界故障地址页表命中权限拒绝映射缺失线程上下文一致等待跨进程资源所有者清楚共享边界泄漏退出完整回收延迟清理仍被访问最终输出正确不能覆盖错误地址、权限或回收状态
专属图示:地址、线程、资源和退出在三类样本下的首个变化。
样本只改变的变量预期判定必存证据
正常映射、权限、线程和资源完整访问可解释,退出能完整回收页表、上下文、状态、清理记录
边界页边界、权限、共享范围或资源容量越过阈值在异常点停止并给出回退阈值、虚拟地址、错误、替代路径
单一故障一个页表项、线程、文件或回收动作失效首个资源异常暴露并恢复首差、所有者、回收和回归

最小进程证据包与反例

证据包包含程序哈希、进程身份、入口参数、虚拟页和页表、权限、物理页、线程上下文、文件与共享资源、调度轨迹、异常、退出码、回收记录和独立复核结果。最终输出正确或进程表消失,只能辅助定位,不能单独证明资源已经安全释放。

反例可以是两个进程的相同虚拟地址指向不同物理页,也可以是共享映射释放后仍有线程访问。发现反例后,保留地址和生命周期轨迹,缩小共享边界、修复权限或回收合同并重放;不要用“通常能运行”替代隔离证据。

术语表

名词解释

本章出现的专业名词,用大白话再讲一遍。

虚拟地址空间

进程看到的地址、代码、数据、堆、栈和映射关系。

页表

把虚拟页号、权限和有效位转换为物理页位置的结构。

进程隔离

让不同进程拥有独立地址与资源视图,并用权限和显式共享边界控制访问。

资源生命周期

从程序装载、资源创建、线程运行、异常处理到退出回收的完整状态范围。

线程

在某个进程地址空间和资源上下文中执行的调度单位。

练习

练习

问题 1: 两个进程都打印出虚拟地址 0x4000,是否说明它们访问同一块物理内存?

问题 2: 线程在进程退出后仍访问共享页面,应该先查哪一处?

问题 3: 一个程序能启动,但分页压力上升后出现错误。你会保存哪些证据?

资料与写作方式声明

本章以码农翻身权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

本页小结

1.5 我是一个进程的关键不是把进程背成一张表,而是能从程序的装载、地址重定位、虚拟内存:分页、线程调度到退出回收追踪所有权和状态。用页表、权限、隔离和生命周期证据解释正常与边界,才能在故障时知道应该暂停、共享、回退还是回收。

讨论

评论区加载中…