
作者qwen3.8-max。一、本章总览1. 计算机系统的基本组成计算机系统由硬件和系统软件组成。二者共同协作用于运行应用程序。虽然具体实现不断变化但系统的基本概念相对稳定。不同计算机系统通常具有相似的硬件和软件组件并执行相似的功能。2. 学习本章的目的理解计算机系统有助于程序员写出更快速、更可靠、更安全的程序理解程序在系统中如何被创建、翻译、加载和执行理解程序性能受哪些因素影响避免常见系统级编程错误例如链接错误、缓冲区溢出、数字表示错误等。二、hello 程序的生命周期本章以经典 C 程序hello.c为例追踪一个程序从创建到运行结束的全过程。#includestdio.hintmain(){printf(hello, world\n);return0;}程序生命周期大致为程序员编写源程序hello.c编译系统将源程序翻译成可执行目标文件helloshell 加载并运行可执行文件程序将字符串输出到屏幕程序终止。三、1.1 信息就是位 上下文1. 源程序的本质hello.c是程序员通过编辑器创建并保存的文本文件。源程序本质上是由0和1组成的位序列。每 8 个位组成一个字节。每个字节表示程序中的某个文本字符。2. ASCII 编码现代计算机系统通常使用 ASCII 标准表示文本字符。每个字符用一个唯一的单字节整数值表示。例如字符ASCII 值#35i105n110c99空格32\n103. 文本文件与二进制文件只由 ASCII 字符构成的文件称为文本文件。其他文件称为二进制文件。4. 核心思想系统中所有信息包括磁盘文件、内存中的程序、内存中的用户数据、网络上传送的数据都是由一串比特表示的。区分不同数据对象的唯一方法是数据对象被读取时的上下文。同样的字节序列在不同上下文中可能表示整数浮点数字符串机器指令其他数据对象。5. 程序员需要理解数字表示的原因计算机中的数字表示与真实整数、实数不同它们是对真值的有限近似可能产生意想不到的行为例如浮点数误差、整数溢出等问题。四、1.2 程序被其他程序翻译成不同的格式1. 为什么需要翻译高级 C 语言程序便于人类阅读但计算机不能直接执行 C 语言源代码必须将 C 语句转换为低级机器语言指令最终打包成可执行目标程序。2. GCC 编译命令在 Unix 系统上gcc-ohello hello.cGCC 编译器驱动程序读取源程序hello.c并翻译为可执行目标文件hello。3. 编译系统的四个阶段hello.c ↓ 预处理器 cpp hello.i ↓ 编译器 cc1 hello.s ↓ 汇编器 as hello.o ↓ 链接器 ld hello四个阶段分别是预处理编译汇编链接。4. 四个阶段详解4.1 预处理阶段执行者预处理器 cpp主要工作根据以#开头的命令修改原始 C 程序例如处理#include stdio.h将头文件stdio.h的内容插入程序文本中输出通常以.i为扩展名。示例hello.c → hello.i4.2 编译阶段执行者编译器 cc1主要工作将 C 程序翻译成汇编语言程序输出文本形式的汇编文件。示例hello.i → hello.s汇编语言的特点用文本格式描述低级机器语言指令是不同高级语言编译器之间的通用输出语言例如 C 和 Fortran 编译器可以产生相同形式的汇编输出。4.3 汇编阶段执行者汇编器 as主要工作将汇编语言程序翻译成机器语言指令打包成可重定位目标程序输出目标文件。示例hello.s → hello.ohello.o是二进制文件。4.4 链接阶段执行者链接器 ld主要工作合并多个目标文件将程序调用的库函数合并进来生成最终可执行目标文件。示例中hello.o printf.o → hello其中printf是 C 标准库函数它位于预编译好的目标文件printf.o中链接器负责将其合并到hello.o中。最终生成可执行目标文件 hello五、1.3 了解编译系统如何工作是大有益处的1. 优化程序性能理解编译系统有助于回答以下问题switch是否总是比if-else高效函数调用的开销有多大while循环是否比for循环更高效指针引用是否比数组索引更高效为什么把循环求和结果放在本地变量中更快为什么重新排列算术表达式中的括号会影响性能后续章节涉及章节内容第3章x86-64 机器语言C 如何翻译成机器代码第5章通过转换 C 代码优化性能第6章存储器层次结构程序如何利用缓存第7章链接、静态库、动态库2. 理解链接时出现的错误常见链接相关问题链接器报告无法解析某个引用静态变量和全局变量的区别不同 C 文件中定义同名全局变量会发生什么静态库和动态库的区别命令行中库的排列顺序有什么影响为什么有些链接错误直到运行时才出现。3. 避免安全漏洞缓冲区溢出是许多网络和服务器安全漏洞的主要原因原因是程序员不理解必须限制来自不受信任源的数据数量和格式学习汇编语言、程序栈、控制信息存储方式有助于理解缓冲区溢出程序员、编译器和操作系统都可以采取措施降低攻击风险。六、1.4 处理器读并解释储存在内存中的指令1. shell 的作用运行hello程序./helloshell 是命令行解释器输出提示符等待用户输入命令如果输入不是内置命令则假定它是一个可执行文件shell 加载并运行该文件等待程序终止。七、1.4.1 系统的硬件组成典型系统的硬件主要包括总线I/O 设备主存处理器。1. 总线总线是贯穿整个系统的电子通道。作用携带信息字节在各个部件之间传递数据。特点总线通常传送定长的字节块称为字字长是基本系统参数常见字长为 4 字节即 32 位或 8 字节即 64 位。2. I/O 设备I/O 设备是系统与外部世界交互的通道。示例设备设备功能键盘用户输入鼠标用户输入显示器用户输出磁盘驱动器长期存储数据和程序每个 I/O 设备通过控制器或适配器连接到 I/O 总线。控制器与适配器控制器位于 I/O 设备本身或主板上的芯片组适配器插在主板插槽上的卡二者功能都是在 I/O 总线和 I/O 设备之间传递信息。3. 主存主存是临时存储设备。作用存放正在执行的程序存放程序处理的数据。物理组成一组 DRAM 芯片。逻辑结构存储器是一个线性的字节数组每个字节有唯一地址地址从 0 开始。数据大小示例在 Linux x86-64 上C 类型字节数short2int4float4long8double84. 处理器CPU即中央处理单元是解释和执行指令的引擎。程序计数器 PCPC 是一个字长大小的寄存器在任何时刻指向主存中的某条机器指令处理器不断执行 PC 指向的指令然后更新 PC使其指向下一条指令。指令执行模型处理器看似按照简单模型执行从 PC 指向的位置读取指令解释指令中的位执行指令指定的操作更新 PC指向下一条指令。下一条指令不一定紧邻刚执行的指令。相关硬件组件寄存器文件一组字长寄存器ALU算术/逻辑单元用于计算数据和地址PC程序计数器。基本操作类型操作含义加载从主存复制一个字节或字到寄存器存储从寄存器复制一个字节或字到主存操作将两个寄存器内容送入 ALU 运算结果存入寄存器跳转从指令中取出一个字覆盖 PC 原来的值指令集架构与微体系结构概念含义指令集架构描述每条机器代码指令的效果微体系结构描述处理器实际如何实现八、1.4.2 运行 hello 程序运行hello的大致过程1. 输入命令用户输入./helloshell 从键盘读取字符并保存到内存中。2. 加载可执行文件用户按下回车后shell 知道命令输入完成shell 执行指令加载可执行文件hello将hello目标文件中的代码和数据从磁盘复制到主存。数据包括hello, world\n3. DMA 技术数据可以不经过处理器直接从磁盘到达主存这种技术称为直接存储器存取DMA。4. 执行程序可执行文件加载到主存后处理器执行main函数中的机器语言指令将字符串从主存复制到寄存器再从寄存器复制到显示设备最终显示在屏幕上。九、1.5 高速缓存至关重要1. 系统性能瓶颈之一计算机系统花费大量时间在不同位置之间复制数据。例如hello程序磁盘 → 主存 → 处理器 → 显示设备这些复制操作是开销会降低程序运行速度。2. 存储设备速度差异基本事实较大的存储设备通常较慢快速设备通常更贵磁盘容量可能远大于主存但磁盘访问速度远慢于主存寄存器文件访问速度远快于主存处理器与主存之间的速度差距还在增大。3. 高速缓存的作用为缓解处理器和主存之间的速度差距引入高速缓存存储器 cache作用作为暂时集结区域存放处理器近期可能需要的信息。4. 多级高速缓存典型结构层级位置特点L1处理器芯片上容量较小速度接近寄存器文件L2通过特殊总线连接处理器容量较大比 L1 慢但比主存快L3较新系统中存在更大但仍然比主存快实现技术L1、L2、L3 通常使用 SRAM主存通常使用 DRAM。5. 局部性原理高速缓存有效的原因是程序具有访问局部区域里的数据和代码的趋势。如果经常访问的数据放在缓存中大部分内存访问可以在快速缓存中完成程序性能可能显著提升。十、1.6 存储设备形成层次结构1. 存储器层次结构思想每个计算机系统中的存储设备都组织成层次结构。从上到下访问速度越来越慢容量越来越大每字节成本越来越低。2. 典型存储器层次结构层级设备说明L0寄存器CPU 寄存器保存来自高速缓存的字L1L1 高速缓存SRAM保存取自 L2 的缓存行L2L2 高速缓存SRAM保存取自 L3 的缓存行L3L3 高速缓存SRAM保存取自主存的缓存行L4主存DRAM保存取自本地磁盘的磁盘块L5本地二级存储本地磁盘保存远程文件L6远程二级存储分布式文件系统、Web 服务器等3. 层次结构的核心思想上一层存储器是下一层存储器的高速缓存。例如寄存器文件 是 L1 的缓存 L1 是 L2 的缓存 L2 是 L3 的缓存 L3 是主存的缓存 主存是磁盘的缓存 本地磁盘可以是远程存储的缓存4. 对程序员的意义程序员理解存储器层次结构后可以优化程序性能减少昂贵访问提高局部性更充分利用缓存。十一、1.7 操作系统管理硬件1. 操作系统的角色应用程序不能直接访问硬件例如键盘显示器磁盘主存。它们必须通过操作系统提供的服务。操作系统可看作应用程序和硬件之间的一层软件。2. 操作系统的两个基本功能功能一保护硬件防止硬件被失控的应用程序滥用。功能二提供统一接口为应用程序提供简单一致的机制用于控制复杂硬件设备。3. 操作系统提供的三个基本抽象抽象抽象对象进程处理器、主存、I/O 设备虚拟内存主存和磁盘文件I/O 设备十二、1.7.1 进程1. 进程的定义进程是操作系统对一个正在运行的程序的抽象。现代系统可以同时进行多个进程每个进程看起来好像独占硬件多个进程并发运行指令交错执行。2. 并发执行并发运行指一个进程的指令和另一个进程的指令交错执行。实现方式处理器在进程之间切换单处理器系统通过时间片模拟并发多核处理器可以真正并行执行多个进程。3. 上下文操作系统需要保存进程运行所需的状态信息。上下文包括PC 的当前值寄存器文件的当前值主存内容其他状态信息。4. 上下文切换当操作系统决定将控制权从当前进程转移到另一个进程时保存当前进程的上下文恢复新进程的上下文将控制权传递给新进程。新进程会从上次停止的地方继续运行。5. shell 运行 hello 的进程过程示例场景最初只有 shell 进程运行用户输入命令shell 通过系统调用请求操作系统运行hello操作系统保存 shell 上下文创建新的 hello 进程将控制权交给 hello 进程hello 运行并终止操作系统恢复 shell 上下文shell 继续等待下一条命令。6. 内核与系统调用内核内核是操作系统代码常驻主存的部分。内核不是独立进程而是系统管理全部进程所用代码和数据结构的集合。系统调用当应用程序需要操作系统服务时执行一条特殊的系统调用指令将控制权传递给内核内核执行请求的操作然后返回应用程序。十三、1.7.2 线程1. 线程的定义现代系统中一个进程可以由多个执行单元组成这些执行单元称为线程。每个线程运行在进程上下文中共享同样的代码和全局数据。2. 线程的重要性线程越来越重要因为网络服务器需要并行处理多线程之间比多进程之间更容易共享数据线程通常比进程更高效在多处理器系统中多线程可提高程序运行速度。十四、1.7.3 虚拟内存1. 虚拟内存的定义虚拟内存是一个抽象概念它为每个进程提供假象好像每个进程都在独占使用主存。每个进程看到的内存是一致的称为虚拟地址空间2. Linux 进程虚拟地址空间结构从低地址到高地址大致包括程序代码和数据堆共享库用户栈内核虚拟内存。3. 各区域说明3.1 程序代码和数据代码从固定地址开始紧接着是与 C 全局变量对应的数据该区域由可执行目标文件初始化。例如hello 可执行文件3.2 堆位于代码和数据区之后可在运行时动态扩展和收缩由malloc、free等函数管理。3.3 共享库大约在地址空间中间存放共享库代码和数据例如 C 标准库、数学库与动态链接有关。3.4 用户栈位于用户虚拟地址空间顶部编译器用它实现函数调用函数调用时栈增长函数返回时栈收缩。3.5 内核虚拟内存位于地址空间最上部保留给操作系统内核应用程序不能直接读写该区域应用程序必须通过系统调用访问内核功能。4. 虚拟内存的基本思想进程的虚拟内存内容可以存储在磁盘上主存作为磁盘的高速缓存处理器生成的每个地址可能需要硬件翻译。十五、1.7.4 文件1. 文件的定义文件就是字节序列。每个 I/O 设备都可以看成文件包括磁盘键盘显示器网络。2. Unix I/O系统中的所有输入输出都通过一组系统函数调用实现Unix I/O3. 文件抽象的意义优点为应用程序提供统一视图屏蔽底层设备差异程序员不必了解具体设备技术同一程序可以运行在使用不同设备技术的系统上。十六、1.8 系统之间利用网络通信1. 网络作为 I/O 设备从单独系统的角度看网络也可以视为一种 I/O 设备。系统可以将字节从主存复制到网络适配器通过网络发送到另一台机器也可以接收来自其他机器的数据并复制到本地主存。2. 网络应用示例网络使信息复制成为计算机的重要用途电子邮件即时通信万维网FTPtelnet。3. telnet 远程运行 hello 的过程步骤用户在本地键盘输入命令客户端向远程 telnet 服务器发送字符串服务器将字符串发送给远程 shell远程 shell 运行 hello 程序远程程序输出hello world\ntelnet 服务器将输出发送回客户端客户端在本地显示器上打印结果。4. 客户端/服务器模型这种交互是网络应用的典型模式客户端发起请求服务器提供服务双方通过网络交换数据。十七、1.9 重要主题1. Amdahl 定律1. 基本思想当对系统的某个部分进行加速时整体性能提升取决于该部分的重要性该部分被加速的程度。2. 公式推导设原执行时间为Told某部分执行时间占比为α该部分加速比为k。则新执行时间为Tnew Told [(1 - α) α / k]系统加速比为S Told / Tnew 1 / [(1 - α) α / k]3. 示例假设α 0.6 k 3则S 1 / (0.4 0.6 / 3) S 1.67说明即使对占比 60% 的部分加速 3 倍整体加速比也只有 1.67 倍。4. Amdahl 定律的结论要想显著加速整个系统必须提升系统中相当大部分的速度。5. 特殊情况某部分加速到时间可忽略当k → ∞时Smax 1 / (1 - α)如果 60% 的系统被加速到几乎不花时间Smax 1 / 0.4 2.5即使某部分被极大优化整体提升仍受其余部分限制。6. 练习题思想练习题 1.1卡车运输例子总距离 2500 公里原速度 100 公里/小时原时间 25 小时蒙大拿州 1500 公里速度提高到 150 公里/小时。关键结论蒙大拿段加速比例为 1.5总时间从 25 小时降到 20 小时整体加速比为25 / 20 1.25×如果要整体加速比达到1.67×蒙大拿段速度需要非常高说明局部优化对整体提升有限。练习题 1.2目标整体性能提升2×可优化部分占80%。求该部分需要提升多少。由2 1 / [(1 - 0.8) 0.8 / k]解得k 2.67十八、1.9.2 并发和并行1. 基本概念并发并发是一个通用概念一个系统同时具有多个活动。并行并行是使用并发使系统运行得更快。2. 三个并行层次本章重点强调三个层次线程级并发指令级并行单指令、多数据并行。十九、线程级并发1. 进程与线程在进程抽象之上可同时运行多个程序一个进程可以有多个线程多个控制流可以共享进程资源。2. 单处理器系统传统系统中一个时刻只能执行一个程序操作系统通过快速切换制造并发假象称为时间共享。3. 多处理器系统多处理器系统由多个处理器组成并由单一操作系统内核控制。4. 多核处理器多核处理器将多个 CPU 核集成到一个芯片上每个核有自己的寄存器和缓存可共享更高层缓存和主存接口。例如四核处理器核0、核1、核2、核3每个核可能有L1 指令缓存L1 数据缓存L2 统一缓存共享 L3 缓存共享主存接口。5. 超线程超线程也称同时多线程特点一个 CPU 可执行多个控制流某些硬件有多个备份如 PC、寄存器文件某些硬件共享如浮点运算单元可以在单个周期内选择执行哪个线程提高 CPU 资源利用率。示例Intel Core i7 每个核可执行两个线程四核系统可并行执行八个线程。6. 多处理器提高性能的两种方式减少模拟并发的开销使多线程程序运行得更快。前提程序必须以多线程方式编写并且线程能够高效并行执行。二十、指令级并行1. 指令级并行的含义现代处理器可以同时执行多条指令。例如早期处理器执行一条指令需要 3 到 10 个周期现代处理器可每个时钟周期执行 2 到 4 条指令。2. 流水线流水线技术将指令执行过程划分为多个阶段每个阶段执行一部分工作各阶段并行处理不同指令的不同部分。例如取指 → 译码 → 执行 → 访存 → 写回效果提高指令吞吐率可接近每周期一条指令。3. 超标量处理器如果处理器能达到比每周期一条指令更快的执行速率则称为超标量处理器特点支持指令级并行可同时发射和执行多条指令现代处理器大多支持超标量操作。二十一、单指令、多数据并行1. SIMD 并行SIMDSingle Instruction, Multiple Data含义一条指令产生多个可以并行执行的操作。例如一条指令同时对 8 对单精度浮点数做加法。2. 应用场景SIMD 常用于图像处理声音处理视频处理科学计算高性能计算。3. 编程方式有些编译器可以自动提取 SIMD 并行性但更可靠的方法是使用编译器支持的特殊向量数据类型例如 GCC 支持的向量类型。二十二、1.9.3 计算机系统中抽象的重要性1. 抽象的意义抽象是计算机科学最重要的概念之一。抽象的作用隐藏实现复杂性提供简单接口使程序员可以安全使用底层机制使系统可移植、可扩展、可维护。2. 指令集架构指令集架构是处理器硬件的抽象。特点机器代码程序看起来像一次只执行一条指令实际硬件可能并行执行多条指令不同处理器实现可以执行相同机器代码但性能和开销可能不同。3. 操作系统抽象操作系统提供三类抽象抽象对应对象文件I/O 设备虚拟内存主存和磁盘进程处理器、主存、I/O 设备4. 虚拟机虚拟机提供对整个计算机的抽象包括操作系统处理器程序。虚拟机思想的优势可运行不同操作系统可运行同一操作系统的不同版本便于隔离和管理便于运行不同环境的程序。二十三、第1章核心概念总表概念核心内容位、字节、ASCII所有信息本质上是位上下文决定含义编译系统C 程序经过预处理、编译、汇编、链接生成可执行文件处理器读取并解释内存中的指令主存临时存储程序和数据I/O 设备系统与外部世界交互的通道总线各组件之间传递数据的通道缓存利用局部性提高访问速度存储器层次结构寄存器、缓存、主存、磁盘形成层次操作系统管理硬件为程序提供抽象进程正在运行程序的抽象虚拟内存每个进程独占内存的假象文件I/O 设备的抽象网络可视为 I/O 设备Amdahl 定律整体加速受未加速部分限制并发与并行多活动系统可用于提升性能抽象隐藏复杂性是系统设计的核心思想二十四、第1章逻辑主线总结本章围绕hello程序展开主要回答四个问题1. 程序如何表示源代码 → 位序列 → ASCII 文本核心思想信息就是位 上下文。2. 程序如何被翻译hello.c → hello.i → hello.s → hello.o → hello核心工具预处理器编译器汇编器链接器。3. 程序如何运行磁盘上的可执行文件 → 主存 → CPU 执行指令 → 输出结果涉及硬件键盘shell磁盘主存CPU显示器。4. 系统如何管理程序操作系统提供三大抽象进程 虚拟内存 文件二十五、适合记忆的重点结论系统中所有信息都是位上下文决定其含义。程序必须经过编译系统翻译成可执行目标文件。编译系统包括预处理、编译、汇编、链接四个阶段。CPU 从内存读取并执行指令。存储器速度差异很大缓存用于弥补处理器和主存之间的速度差距。存储设备形成层次结构高层设备是低层设备的缓存。操作系统管理硬件并提供进程、虚拟内存和文件三个抽象。网络也是一种 I/O 设备。Amdahl 定律说明系统整体性能提升受未优化部分限制。抽象是计算机系统中最重要的设计思想之一。