引言
计算机系统是由硬件和系统软件组成的,它们共同工作来运行应用程序。
1.1 信息就是 位 + 上下文
ASCII标准:用一个唯一的单字节大小的整数值来表示每个字符。大部分的现代计算机系统都使用 ASCII 标准来表示文本字符。
程序的生命周期:从一个源程序(或者说源文件)开始,即程序员通过编辑器创建并保存的文本文件。
源程序:实际上就是一个由值0和1组成的位(又称为比特)序列,8个位被组织成一组,称为字节。每个字节表示程序中的某些文本字符。
基本思想:
系统中所有的信息,包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。
区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。
1.2 程序被其他程序翻译成不同的格式
编译器驱动程序:将源文件转化为目标文件
编译系统 compilation system:预处理器、编译器、汇编器和链接器
预处理阶段
hello.c(文本) → hello.i(文本)
预处理器(CPP)
读取系统头文件的内容,并把它直接插入程序文本中。
编译阶段
hello.i(文本) → hello.s(文本)
编译器(ccl)
生成汇编语言程序
。
汇编阶段
hello.s(文本) → hello.o(二进制)
汇编器(as)
将 hello.s 翻译成机器语言指令
,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)
的格式,并将结果保存在目标文件 hello.o 中。
链接阶段
hello.o + printf.o → hello 可执行目标程序(二进制)
链接器 (ld)
处理调用合并,得到可执行目标文件
,可以被加载到内存中,由系统执行。
1.3 了解编译系统如何工作是大有益处的
- 优化程序性能
- 理解链接时出现的错误
- 避免安全漏洞
1.4 处理器读并解释储存在内存中的指令
使用命令行解释器(shell)加载并运行hello程序。
1.4.1 系统的硬件组成
① 总线
贯穿整个系统的一组电子管道。
携带信息字节并负责在各个部件间传递。
② I/O 设备
系统与外部世界的联系通道,如键盘、鼠标、显示器、磁盘等。
每个 I/O 设备都通过一个 控制器 或 适配器 与 I/O 总线相连。
💡 控制器和适配器之间的区别:主要在于它们的封装方式
控制器: I/O 设备本身或者系统的主印制电路板(通常称作主板)上的芯片组。
适配器: 一块插在主板插槽上的卡。
③ 主存
临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。
物理上,由一组动态随机存取存储器(DRAM)
芯片组成。
逻辑上,一个线性的字节数组,每个字节都有其唯一的地址(数组索引)。
④ 处理器
解释(或执行)存储在主存中指令的引擎。
程序计数器(PC)
:一个大小为一个字的存储设备,是处理器的核心。在任何时刻,PC 都指向主存中的某条机器语言指令(即含有该条指令的地址)。
1.4.2 运行 hello 程序
输入命令
加载可执行文件(通过 DMA 技术)
输出结果
1.5 高速缓存至关重要
局部性原理:程序具有访问局部区域里的数据和代码的趋势。
高速缓存存储器 cache memory:暂时的集结区域,存放处理器近期可能会需要的信息。由静态随机访问存储器(SRAM)
硬件技术实现。
1.6 存储设备形成层次结构
主要思想:上一层的存储器作为低一层存储器的高速缓存。
1.7 操作系统管理硬件
操作系统:应用程序和硬件之间插入的一层软件,所有应用程序对硬件的操作尝试都必须通过操作系统。
基本功能:
- 防止硬件被失控的应用程序滥用
- 向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备
抽象概念:进程、虚拟内存、文件
1.7.1 进程
进程是操作系统对一个正在运行的程序的一种抽象。
并发运行:一个进程的指令和另一个进程的指令交错执行。在大多数系统中,通过处理器在进程间切换来实现 需要运行的进程数 > 可以运行它们的 CPU 个数。
上下文:进程运行所需的所有状态信息。比如 PC 和寄存器文件的当前值,以及主存的内容。
1.7.2 线程
一个进程实际上可以由多个称为线程的执行单元组成, 每个线程都运行在进程的上下文中,并共享同样的代码和全局数据 。
1.7.3 虚拟内存
虚拟内存:一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地使用主存。
每个进程看到的内存都是一致的,称为虚拟地址空间
。
程序代码和数据
对所有的进程来说,代码是从同一固定地址开始,紧接着的是和 C 全局变量相对应的数据位置。
代码和数据区是直接按照可执行目标文件的内容初始化的。
代码和数据区在进程一开始运行时就被指定了大小。
堆
堆可以在运行时动态地扩展和收缩。
共享库
大约在地址空间的中间部分是一块用来存放像 C 标准库和数学库这样的共享库的代码和数据的区域。
栈
位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。
和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。
内核虚拟内存
地址空间顶部的区域是为内核保留的。
不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。它们必须调用内核来执行这些操作。
1.7.4 文件
文件就是字节序列。
每个 I/O 设备,包括磁盘、键盘、显示器,甚至网络,都可以看成是文件。
它向应用程序提供了一个统一的视图,来看待系统中可能含有的所有各式各样的 I/O 设备。
1.8 系统之间利用网络通信
网络也可以视为一种 I/O 设备。
1.9 重要主题
1.9.1 Amdahl 定律
当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度。
总的执行时间
Told = 系统执行某应用程序需要时间
α = 系统某部分所需执行时间与总时间的比例
k = 该部分性能提升比例
加速比
1.9.2 并发和并行
并发(concurrency):一个同时具有多个活动的系统
并行(parallelism):用并发来使一个系统运行得更快
1. 线程级并发
2. 指令级并行
3. 单指令、多数据并行
1.9.3 计算机系统中抽象的重要性
虚拟机:对整个计算机的抽象,包括操作系统、处理器和程序。