《深入理解计算机系统》读书笔记
2021-05-09 07:20:46 0 举报
AI智能生成
计算机系统
作者其他创作
大纲/内容
深入理解计算机系统
计算机系统漫游
1. 信息就是【位/Bit】+【上下文】
C语言
C语言与Unix操作系统关系密切
C语言小而美
C语言是为了实践目的设计的
C语言是系统编程的首选
2. 程序被其他程序翻译成不同的格式
GCC编译器驱动程序
源文件
可执行目标文件
编译系统
源文件(文本)【hello.c】
预处理器(cpp)
修改了的源程序(文本)【hello.i】
编译器(ccl)
汇编程序(文本)【hello.s】
汇编器(as)
可重定位目标程序(二进制)【hello.o】
链接器(ld)
可执行目标二进制(二进制)
GCC【GNU's Not Unix 】
EMACS 编译器
GCC 编译器
GDB 调试器
汇编器
链接器
处理二进制文件的工具
翻译系统【四个阶段】
预处理阶段/预处理器(cpp)
编译阶段/编译器(app)
汇编阶段/汇编器(as)
链接阶段/链接器(ld)
3. 了解编译系统是如何工作是大有益处的
优化程序性能
理解链接时出险的错误
避免安全漏洞
4. 处理器读并解释存储在内存中的指令
运行 hello 程序
5. 高速缓存至关重要
静态随机访问存储器(font face=\
L1
L2
L3
Cache Memory
6. 存储设备形成层次结构
7. 操作系统管理硬件
进程
进程是操作系统对一个正在运行的程序的一种【抽象】
【上下文】操作系统保持跟踪进程运行所需的所有状态信息
上下文切换
操作系统内核 kernel
系统调用 systemcall
线程
执行单元
虚拟内存
文件
8. 系统之间利用网络通信
9. 重要主题
Amdahl 定律
当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程度
要想显著加速整个系统,必须提升全系统中相对大的部分速度
并发和并行
并行,span style=\
并发,span style=\
线程级并发
指令级并行
单指令、多数据并行
【抽象】是计算机科学中最为重要的概念之一
10. 小结
计算机系统是由【硬件】和【系统软件】组成的
计算机系统分层
硬件(处理器/主存/IO设备)
操作系统
应用系统
计算机系统中【抽象】的重要性
虚拟机
指令集架构
处理器
主存
I/O设备
计算机科学领域的任何问题都可以增加一个间接的中间层来解决
系统硬件主要4个组成部分
总线
I/O总线
I/O桥
系统总线【CPU】
内存总线【内存】
总线接口【CPU】
IO设备
鼠标【USB 控制器】
键盘【USB 控制器】
显示器【图形适配器】
磁盘【磁盘控制器】
网络【网络适配器】
主存器
动态随机存取存储器 DRAM
处理器(CPU)
程序计算器 PC【1个字】
算术/逻辑单元 ALU
寄存器文件【1个字】
高速缓存存储器
总线接口
操作系统管理硬件
虚拟内存【进程的虚拟地址空间】
内核虚拟内存
【用户】栈
共享库
【运行时】堆
程序代码和数据
存储设备形成层次结构
L0 寄存器
L1 高速缓存(SRAM)
指令/数据级缓存
L2 高速缓存(SRAM)
核级缓存
L3 高速缓存(SRAM)
CPU级缓存
L4 主存(DRAM)
L5 本地二级缓存
本地磁盘
L6 远程二级缓存
分布式文件系统
Web 服务器
程序结构和执行
第二章 信息的表示和处理
1. 信息存储
数字表示
无符号【表示大于或等于0的数字】
补码【表示负数】
浮点数
【字节】是最小的可寻址的内存单元【byte = 8 bit】
计算机信息编码为【位】
程序对象
程序数据
指令
控制信息
十六进制表示法
0x/0X
二进制
十进制
字数据大小
32位/4G/32位程序
64位/16EB/64位程序
寻址和字节顺序
对象的地址
排列
字节是最小的可寻址的内存单元
字节数组
虚拟内存VM
地址
内存字节表示
地址集合
虚拟地址空间
表示字符串
表示代码
布尔代数简介
C语言中的位级运算
C语言中的逻辑运算
C语言中的移位运算
2. 整数表示
整形数据类型
无符号的编码
补码编码
有符号数和无符号数之间的转换
C语言中的有符号数的转换
扩展一个数字的位表示
截断数字
关于有符号数与无符号数的建议
3. 整数运算
无符号加法
补码加法
补码的非
无符号乘法
补码乘法
乘以常数
除以2的幂
关于整数运算的最后思考
4. 浮点数
二进制小数
IEEE浮点表示
数字实例
舍入
浮点运算
C语言中的浮点数
5. 小结
本章描述计算机的算术运算
第三章 程序的机器级表示
1. 历史观点
摩尔定律
2. 程序编码
机器级代码
抽象
利用简单的抽象模型【隐藏实现的细节】
机器级编码的两种重要抽象
「指令」 【指令集体系结构或指令集架构 ISA Instruction Set Architecture】抽象机器级程序的格式和行为,定义处理器状态、指令格式,以及每条指令对状态的影响
「地址」【机器级程序使用内存地址的虚拟地址】提供的内存模型看上去是一个非常大的字节数组
用字节序列编码低级的操作
处理数据
管理内存
读写存储设备上的数据
利用网络通信
机器级编码抽象
指令集体系结构或指令集架构
指令【指令集体系结构或指令集架构 ISA Instruction Set Architecture】
机器级程序的格式和行为
处理器状态、指令格式,以及每条指令对状态的影响
虚拟地址
地址【机器级程序使用内存地址的虚拟地址】
机器级程序使用的内存地址
内存模型
非常大的字节数组
计数器
程序计数器 PC/下一条指令在内存的地址
整数计数器
条件码计数器
向量计数器/浮点数
程序内存
可执行机器代码
运行时栈
用户分配的内存块
3. 数据格式
char【字节、1字节】
short【字、2字节】
int【双字、4字节】
long【四字、8字节】
char*【四字、8字节】
float【单精度、4字节】
double【双精度、8字节】
4. 访问信息
操作数指示符
立即数
寄存器
内存引用
数据传输指令
MOV
压入和弹出栈传输数据
pushq
popq
5. 算术和逻辑操作
加载有效地址
load effective address
leaq
一元操作
INC
DEC
NEG
NOR
二元操作
ADD
SUB
IMUL
XOR
OR
AND
移位操作
SAL
SHL
SAR
SHR
特殊的算术操作
6. 控制
控制
非直线代码行为
条件码
条件码寄存器
【CF】进位标志
【ZF】零标志
【SF】符号标志
【OF】溢出标志
访问条件码
SET
CMP
跳转指令
jump
跳转指令的编码
用条件控制来实现条件分支
用条件传送来实现条件分支
循环
do-while
while
for
switch语句
根据一个整数索引值进行多重分支
跳转表
7. 过程
过程
传递过程
传递数据
分配和释放内存
转移控制
栈上的局部存储
寄存器中的局部存储空间
寄存器组是唯一被所有过程共享的资源
递归过程
8. 数组分配和访问
基本原则
指针运算
嵌套的数组
定长数组
变长数组
9. 异质的数据结构
结构
联合
数据对齐
10. 在机器级程序中将控制与数据结合起来
理解指针
每个指针都对应一个类型
每个指针都有一个值
指针用&运算符创建
*操作符用于间接引用指针
数组与指针紧密联系
将指针从一种类型强制转换成另一种类型,只改变它的类型,而不改变它的值
指针也可以指向函数
应用:使用GDB调试器
内存越界引用和缓存区溢出
对抗缓冲区溢出攻击
支持变长栈帧
11. 浮点代码
浮点传递和转换操作
过程中的浮点代码
浮点运算操作
定义和使用浮点常数
在浮点代码中使用位级操作
浮点比较操作
对浮点代码的观察结论
12. 小结
程序是以指令序列来表示的,每条指令都完成一个单独的操作
汇编代码与原始代码的关系
关键找到程序值和寄存器之间的隐射关系
机器代码
读写存储设备的数据
编译器经过一系列的阶段生成机器代码
基于编程语言的规则
基于目标机器的指令集和操作系统遵循的惯例
「GCC C语言」【编译器】以「汇编代码」形式输出(汇编代码是机器代码的文本表示)
「汇编代码」经过【汇编器】和【链接器】生成「可执行的机器代码」
条件
跳转
开关
操作数
立即数/Immediate/常数
寄存器/Register/内存的数值
存储器/Memory/内存引用/地址
数据结构
数组
第四章 处理器体系结构
1. Y86-64 指令集体系结构(ISA)
程序员的可见的状态
RF: 程序寄存器
CC: 条件码
Stat: 程序状态
PC: 程序计数器
DMEM: 内存
指令集体系结构 Instruction-Set Architecture ISA
一个处理器支持的指令和指令的字节级编码
【指令】+【指令编码】
ISA 编译器编写者和处理器设计者之前的概念抽象层
ISA = 指令 + 指令编码 + 异常 + 程序
2. 逻辑设计和硬件控制语言(HCL)
数字系统组成
技术对位进行操作的函数的组合逻辑
存储位的存储器单元
控制存储器单元更新的时钟信号
组合逻辑
逻辑门:数字电路的基本计算单元
组合电路和HCL布尔表达式
字级的组合电路和HCL整数表达式
集合关系
存储器和时钟
状态
程序寄存器
程序计算器
内存
状态寄存器
时序电路 Sequential Circuit
有状态并且在这个状态上进行计算的系统,我们必须引入按位存储信息的设备
时钟是一个周期性信号
存储设备是同一个时钟控制的
时钟寄存器=寄存器
随机访问存储器=内存
3. Y86-64的顺序实现(SEQ)
SEQ 实现一个高效的、流水线化的处理器
PC 程序计数器是SEQ 中唯一的时钟寄存器
将处理组织成阶段
1. 取指【指令内存】【PC】
从内存读取指令字节
地址为程序计数器(PC)的值
2. 译码【寄存器文件】
3. 执行【CC】【ALU】
CC 条件码寄存器
4. 访存【数据内存】
数据写入内存
内存读出数据
地址+数据
5. 写回【寄存器文件】
6. 更新PC【PC】
将PC更新下一个指令
SEQ 硬件结构
指令内存
PC
寄存器文件
条件寄存器
ALU
数据内存
SEQ的时序
时钟寄存器
程序计数器
随机访问存储器
4. 流水线的通用原理
流水线化让不同阶段并行操作
计算流水线
流水线操作的详细说明
流水线的局限性
带反馈的流水线系统
5. Y86-64 的流水线实践
SEQ+:重新安排计算阶段
电路重定时 Circuit Retiming
流水化处理器 Pipe-lined processor
插入流水线寄存器
对信号进行重新排列和标号
预测下一个PC
流水线冒险
冒险:一条指令的位置或操作数依赖于其他仍在流水线中的指令
异常处理
PIPE各阶段的实现
流水线控制逻辑
性能分析
未完成的工作
6. 小结
基本的组合和时序逻辑元素
指令集体系结构 ISA Instruction Set Architecture
SEQ
顺序执行
硬件控制语言 HCL Hardware Control Language
流水化的处理器 Pipe-lined processor
SEQ+
并行执行
作用
处理器是非常有趣而且很重要的
帮助理解整个计算机系统如何工作
许多人设计包含处理器的硬件系统
你的工作可能就是处理器设计
处理器设计重要经验
管理复杂性是首要问题
我们不需要直接实现ISA
硬件设计人员必须非常谨慎小心
第五章 优化程序性能
1. 优化编译器的能力和局限性
2. 表示程序性能
3. 程序实例
4. 消除循环的低效率
5. 减少过程调用
6. 消除不必要的内存引用
7. 理解现代处理器
整体操纵
功能单元的性能
处理器操作的抽象模型
8. 循环展开
9. 提高并行性
多个积累变量
重新结合变换
10. 优化合并代码的结果小结
11. 一些限制因素
寄存器溢出
分支预测和预测错误处罚
12. 理解内存性能
加载的性能
存储的性能
13. 应用:性能提高技术
高级设计
数据结构和算法
基本编码原则
消除连续的函数调用
消除不必要内存引用
正确的编码
低级优化
展开循环,降低消耗
提高指令级并行
编译采用条件数据传递
14. 确认和消除性能瓶颈
程序剖析
使用剖析程序来指导优化
15. 小结
高效程序
高效可执行的源代码
并行计算
程序优化
消除不必要工作
利用处理器指令级并行能力
第六章 存储器层次结构
1. 存储技术
随机访问存储器(RAM)
静态的 SRAM/高速缓存
动态的 DRAM/主存/内存模块
传统的DRAM
内存模块
增强的DRAM
访问主存
总线事务
系统总线
内存总线
非易失的存储器(ROM)
只读存储器(Read-Only Memory ROM)
闪存
固件【存储在ROM上的程序】
固态硬盘(Solid State Disk SSD)
构件
闪存翻译层(固件)
块
页
SSD随机访问VS旋转磁盘
磁盘存储
磁盘构件
磁盘
主轴
盘片
表面
磁道
扇区
磁盘驱动器
旋转磁盘
磁盘容量
记录密度
磁道密度
面密度
扇区访问时间
寻道时间
旋转时间
传送时间
逻辑磁盘块
连接IO设备
USB 通用串行总线 Universal Serial Bus
鼠标
固态硬盘
键盘
图形适配器
监视器
网络适配器
访问磁盘
2. 局部性
局部性原理
时间局部性
空间局部性
对程序数据引用的局部性
取指令的局部性
局部性小结
有良好局部性的程序比局部性差的程序运行得更快
3. 存储器层次结构
缓存结构
数据对象组块 chunk
块 block
存储层次结构
L1 高速缓存
L2 高速缓存
L3 高速缓存
L4 主存
L5 本地二级缓存(本地磁盘)
L6 远程二级缓存(分布式文件系统、Web服务器)
存储器层次结构概念小结
CPU寄存器【L0】
缓存字节
缓存在芯片的CPU寄存器
由编译器管理
TLB【L0】
地址翻译
缓存在芯片上的TLB
由硬件MMU管理
高速缓存【L1】
缓存64字节块
缓存在芯片上的L1高速缓存
由硬件管理
CPU核独享
高速缓存【L2】
缓存在芯片上的L2高速缓存
CPU核独享或共享
高速缓存【L3】
缓存在芯片上的L3高速缓存
全部CPU核共享
虚拟内存【L4 主存】
缓存4KB页
缓存在主存
由硬件+OS管理
与CPU直接交换数据
缓冲区缓存【L4 主存】
缓存部分文件
由OS管理
磁盘缓存【L5 本地二级存储】
缓存磁盘扇区
缓存在磁盘控制器
由控制器固件管理
网络缓存【L5 本地二级存储】
缓存在本地磁盘
NFS客户管理
浏览器缓存【L5 本地二级存储】
缓存WEB页
由WEB浏览器管理
WEB缓存【L6 远程二级存储】
缓存在运程服务器磁盘
由Web代理服务器管理
4. 高速缓存存储器
高速缓存存储器/高速缓存组/高速缓存行
高速缓存组 cache set(一个或多个行的集合)组织结构
高速缓存行 cache line(行是高速缓存的容器)
有效位
标记位
标记
组索引
块偏移
数据块 block(固定信息大小的包)
直接映射高速缓存
组相联高速缓存
全相联高速缓存
5. 编写高速缓存友好的代码
6. 综合:高速缓存友好的代码
存储器山
重新排列循环以提高空间局部性
在程序中利用局部性
7. 小结
核心概念
存储器系统
CPU寄存器
主存储器
存储器层次结构
局部性
SRAM 存储器
DRAM 存储器
内存控制器
寻道
通用串行总线 Universal Serial Bus USB
主机总线适配器
磁盘控制器
内存映射
闪存翻译器
计算机系统模型
CPU执行指令
存储器系统为CPU存储指令和数据
计算机系统的思想
如何将数据在存储器层次结构中上上下下移动(总线)
访问相同的数据项集合
访问相邻的数据项集合
存储技术 访问时间差
计算机软件利用局部性
存储器系统概念模型,它是一个有一致访问时间的线性数组
存储器系统是一个由不同容量、造价和访问时间的存储设备组成的层次结构
存储器类型
1. Register 寄存器
1 ns
< 1KB
2. cache 高速缓存
2 ns
4 MB
3. Memory 主内存(主存)
10 ns
1~16 GB
4. Disk 硬盘
10 ms
1~4T
存储器三种特性
速度足够快
容量足够大
价格足够便宜
基本存储技术
随机存储器(RAM)
SRAM
DRAM
只读存储器(ROM)
只读存储器 ROM
闪存 Flash Memory
固态硬盘 SSD
在系统上运行程序
第七章 链接
1. 编译器驱动程序
源文件(如xx.c)
语言预处理器
编译器
可重定向目标文件(如xx.o)
符号解析
重定位
完全链接的可执行目标文件
2. 静态链接(静态链接器)
符号引用和符号定义关联
一个函数
一个全局变量
一个静态变量
符号定义和内存位置关联起来
3. 目标文件
可重定位目标文件
在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件
可以被直接复制到内存并执行
共享目标文件
在加载时或者运行时被动态地加载进内存并链接
4. 可重定位目标文件
5. 符号和符号表
全局符号
外部符号
局部符号
6. 符号解析
链接器解析多重定义的全局符号
静态库【目标文件打包成一个单独的文件】
与静态库链接
链接器使用静态库来解析引用
7. 重定位
步骤一:重定位节和符号定义
步骤二:重定位符号引用
重定位条目【数据结构】
重定位PC相对引用
重定位绝对引用
8. 可执行目标文件
只读内存段(代码段)
ETF头
段头部表【将连续的文件节映射到运行时内存段】
读/写内存段(数据段)
不加载到内存的符号表和调试信息
节头部表【描述目标文件的节】
9. 加载可执行目标文件
加载器:将可执行文件的内容映射到内存,并运行这个程序
内核内存
用户栈,含栈指针【运行时创建】
共享库的内存映射区域
读写段【从可执行文件中加载】
只读代码段【从可执行文件中加载】
10. 动态链接共享库
静态库缺陷:需要定期维护和更新
解决静态库缺陷的一个现代创新产物
允许多个正在运行的进程共享内存中相同的库代码,因而节约宝贵的内存资源
共享目标
动态链接
共享库可以加载到任意的内存地址,并和一个在内存中的程序链接起来
动态链接器
动态链接库(DLL)
动态链接库过程
源文件(xxx.c;xxx.h)
【翻译器】
可重定向目标文件(xxx.o)
重定位和符号表信息(xxx.so)
【链接器】
部分链接可执行目标文件
【加载器】
代码和数据(xxx.so)
【动态链接器】
内存中完全链接的可执行文件
11. 从应用程序中加载和链接共享库
分发软件
构建高性能Web服务器
12. 位置无关代码
位置无关代码(PIC),加载无需重定位的代码
Position-Indendent Code PIC
PIC 数据引用
PIC 函数引用
延迟绑定
过程链接表(PLT)
全局偏移量表(GOT)
13. 库打桩机制
允许截获共享函数的调用,取而代之执行自己的代码
目标函数
包装函数
即是【拦截器】
编译时打桩
链接时打桩
运行时打桩
14. 处理目标文件的工具
链接
编译时
加载时
运行时
分离编译
编译器驱动程序
由翻译器和汇编器生成
由链接器生成
符号
符号表
静态链接
静态库
存档
静态链接器
重定位条目
重定位符号引用
目标文件
目标模块
动态链接共享库
过程链接表
全局偏移量表
位置无关代码
库打桩机制
链接:将各种代码和数据片段收集并组合成为一个单一文件的过程,这个文件可被加载(复制)到内存并执行
链接的意义
构件大型程序
避免一些危险的编程错误
理解语言的作用域规则是如何实现的
理解其他重要的系统概念
利用共享库
执行时机
编译时(compile time)
源代码翻译成机器代码
加载时(load time)
程序被加载器加载到内存
运行时(run time)
由应用程序执行
静态编译器(编译时)
由编译驱动程序调用(GCC)
将多个可重定位目标文件合并成一个单独的可执行目标文件
动态链接器(加载时和运行时)
通过加载共享库和重定位程序中的引用来完成链接任务
可重定位的目标文件
可执行的目标文件
共享的目标文件
链接器主要任务
将目标文件中全局符号绑定到一个唯一定义
确定符号的最终内存地址,并修改对那些目标的引用
第八章 异常控制流
1. 异常
异常
异常是异常控制的一种形式,它一部分由硬件控制,一部分由操作系统实现
异常控制流的一种形式,它一部分由硬件实现,一部分由操作系统实现【硬件和软件结合】
异常由于一部分是硬件实现的,所以具体细节将随着系统的不同而有所不同【硬件:异常表基址寄存器】
控制流的突变,用来响应处理器状态中的某些变化
事件【状态变化】
异常表
异常处理程序【子程序】
异常号
一些号是由处理器的设计者分配的
一些号由操作系统内核的设计者分配的
异常表基址寄存器(exception Table base register)【CPU】【异常表的起始地址】
异常的类别
中断 interrupt
中断是异步发生的
来自处理外部的IO设备的信号的结果
将控制返回下一个指令
中断处理程序(Interrupt Handle)
陷阱 trap
有意的异常,是执行一条指令的结果
系统调用,用户程序和内核之间系统调用
故障 fault
由错误引起的,它可能被故障处理程序修正
终止 abort
不可恢复的致命错误造成的结果
异常的类型
来自IO设备的信号
异步
返回到下一条指令
中断处理程序 interrupt handler
陷进 trap
有意的异常
同步
返回到syscall之后指令
故障指令 faulting instruction
潜在可恢复的错误
要么重新执行当前指令,要么终止
不可恢复的错误
终止,不会返回
Linux/x86-64系统中的异常
故障和终止
除法错误
一般保护故障
缺页
机器检查
操作系统定义的异常
系统调用
read/读文件
write/写文件
open/打开文件
close/关闭文件
state/获得文件信息
mmap/将内存页映射到文件
brk/重置堆顶
dup2/复制文件描述符
pause/挂起进程直到信号到达
alarm/调度告警信号的传递
getid/获得进程的ID
fork/创建进程
execve/执行进程
_exit/终止进程
wait4/等待一个进程终止
kill/发送信号到一个进程
2. 进程
一个执行中程序的实例
上下文【进程状态】
内核重新启动一个被抢占的进程所需的状态
对象的值
通用目的【寄存器】
浮点寄存器
用户栈
内核栈
内核数据结构
内容
描述地址空间的【页表】
当前进程信息的【进程表】
已打开文件的【文件表】
逻辑控制流
逻辑流
异常处理程序
信号处理程序
假象:独占处理器
时间片:time slice
并发流
一个逻辑流的执行在时间上与另一个流重叠
并发
多个流并发地执行
多个流时间上重叠
多任务
一个进程和其他进程轮流运行
时间分片 time sliceing
私有地址空间
进程为每个程序提供它自己的私有地址空间
进程地址空间
内核虚拟内存【用户代码不可见的内存】
代码
数据
堆
栈
用户栈【运行时创建的】
运行时堆(用 malloc 创建的)
读写段【从可执行文件加载】
只读代码段【从可执行文件加载】
假象:独占内存
用户模式和内核模式
模式位 model bit
设置模式位为内核模式反之为用户模式
内核模式
可以访问特权指令
任何指令
任何内存地址
用户模式
用户模式切换到内核模式唯一办法是通过异常
linux 通过/proc 文件系统 允许用户模式访问内核数据结构
一种异常控制流
进程的状态
内核调度
调度器
内核
主要工作
保存当前进程的上下文
恢复某个先前被抢占的进程被保存的上下文
将控制传递给这个新恢复的进程
调度时机
当内核代表用户执行系统调用时,可能发生上下文切换
中断也可能引发上下文切换
3. 系统调用错误处理
4. 进程控制
获取进程ID
创建和终止进程
运行
停止/挂起
SIGSTOP
SIGTSTP
SIGTTIN
SIGTTOU
SIGCONT/继续
终止
收到终止进程的信号
从主程序返回
调用exit函数
回收子进程
让进程休眠
sleep
pause
加载并运行程序
利用fork和execve运行程序
5. 信号
信号术语
发送信号
/bin/kill
kill 函数
alarm 函数
...
接收信号
进程终止
进程终止并转储内存
进程停止(挂起)直到被 SIGCONT 信号重启
进程忽略该信号
阻塞和解除阻塞信号
显式阻塞机制
隐式阻塞机制
编写信号处理程序
1. 安全的信号处理
处理程序要尽可能简单
在处理程序中只调用异步信号安全的函数
保存和恢复errno
阻塞所有的信号,保护对共享全局数据结构的访问
用volatile声明全局变量
用sig_atomic_t 声明标志
2. 正确的信号处理
3. 可移植的信号处理
signal 函数的语义各有不同
系统调用可以被中断
同步流以避免讨厌的并发错误
显式地等待信号
6. 非本地跳转
7. 操作进程工具
STRACE
PS
TOP
PMAP
8. 小结
异常控制流(Exceptional Control Flow)ECF
有助于理解系统概念
有助于理解应用程序是如何与操作系统交互的
有助于编写新的应用程序
有助于理解并发
有助于理解异常是如何工作的
进程两个重要抽象
【逻辑控制流】它提供给每个程序一个假象,好像它在独占地使用处理器
【私有地址空间】它提供给每个程序一个假象,好像它在独占地使用内存
事件
异常表基址寄存器
中断
陷阱
故障
中断处理程序(硬件)
故障指令
系统调用(syscall)
上下文
时间片
时间分片
并行流
并行地运行
并行地执行
内核模式/超级用户模式
调度
僵死进程
信号
可移植的信号处理
非本地跳转
第九章 虚拟内存
1. 物理和虚拟寻址
内存管理单元(CPU)
虚拟寻址
0 处理器【CPU】
1 虚拟地址(VA)
2 地址翻译(AT)【内存管理单元(MMU)】
页表
页表内容由操作系统提供
3 物理地址(PA)
4 主存
2. 地址空间
一个非负整数地址的有序集合【线性地址空间】
物理地址空间
3. 虚拟内存作为缓存的工具
虚拟内存如何作为缓存
虚拟页VP【Page】【存储在磁盘上】【分割虚拟内存】
未分配的
缓存的
未缓存的
物理内存
物理页/页帧PF【Page Frame】【缓存在DRAM中】【分割物理内存】
DRAM缓存的组织结构
页表PT
页表条目(PTE Page Table Entry)的数组
地址字段
常驻物理内存
页命中
缺页/DRAM缓存不命中
分配页面
又是局部性救了我们
4. 虚拟内存作为内存的工具
简化链接
简化加载
memory mapping
虚拟页与文件的任意位置
mmap
简化共享
简化内存分配
5. 虚拟内存作为内存保护的工具
6. 地址翻译
使用页表的地址翻译
页表基址寄存器(PTBR:Page Table Base Register)
物理页号
保护位
修改位和访问号
高速缓存静止位
内存管理单元【MMU】Memory Management Unit
虚拟页号 VPN Virtual Page Number
虚拟页偏移量 VPO Virtual Page Offset
物理地址
物理页号 PPN Physical Page Number
物理页偏移量 PPO Physical Page Offset
结合高速缓存和虚拟内存
利用TLB加速地址翻译
翻译后备缓冲器 TLB Translation Lookaside Buffer
一个小的、虚拟地址的缓存
多级多页【多级页表】
倒排页表
综合:端到端的地址翻译
内存按字节寻址
内存访问
页面大小
TLB
物理寻址
7. 案例研究:Intel Core i7/Linnux 内存系统
Core i7 地址翻译
一个 Linux 进程的虚拟内存
进程虚拟内存
已初始化数据
未初始化数据
运行时堆
进程相关数据结构
task 和 mm结构
内核代码和数据
Linux 虚拟内存区域
段(Segment)
区域(Area)
连续片(chunk)
8. 内存映射
Linux 将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容
如果虚拟内存系统可以集成到传统的文件系统中,那么就能提供一种简单而高效的把程序和数据加载到内存中的方法
虚拟内存可以映射到两类类型的对象
Linxu 文件系统中的普通文件
匿名文件
共享对象
一个对象可以被映射到虚拟内存的一个区域
共享区域/共享对象
私有区域/私有对象
写时复制 copy-on-write
私有对象
两个私有对象映射到它们虚拟内存的不同区域,但是共享这个对象同一个物理副本
当进程试图写私有的写时复制区域中的一个页面而引起的,将在物理内存中创建这个页面的一个新副本,更新这个新创建的新副本,当解除写时复制约束,CPU 重新执行这个写操作
fork函数
分配独立PID
分配独立虚拟内存
父子进程充分利用 写时复制 特性
execve函数
加载和执行程序
步骤
删除已存在的用户区域
映射私有区域
映射共享区域
设置程序计数器
mmap函数
创建新的虚拟内存区域,并将对象映射到这些区域中
munmap函数
删除虚拟内存区域
9. 动态内存分配
动态内存分配器 dynamic memory allocator
显式分配器
隐式分配器
也叫垃圾收集器
动态内存分配器维护的一个进程的虚拟内存区域
malloc 和 free 函数
malloc 堆中分配块
free 堆中释放块
为什么要使用动态内存分配
动态内存分配的最重要的原因是经常直到程序实际运行时,才知道某些数据结构的大小
分配器的要求
处理任意请求序列
立即响应请求
只使用堆
对齐块
不修改已分配的块
分配器的目标
最大化吞吐率
最大化内存利用率
碎片
隐式空闲链表
放置已分配的块
分割空闲块
获取额外的堆内存
合并空闲块
带边界标记的合并
显式空闲链表
分离的空闲链表
实现问题
综合:实现一个简单的分配器
10. 垃圾收集
垃圾收集器的基本知识
垃圾收集器把内存视为一张有向可达图
Mark&Sweep垃圾收集器
标记清除
C程序的保守Mark&Sweep
11. C程序中常见的与内存有关的错误
1. 间接引用坏指针
2. 读未初始化的内存
3. 允许栈缓冲区溢出
4. 假设指针和它们指向的对象是相同大小的
5. 造成错位错误
6. 引用指针,而不是它所指向的对象
7. 误解指针运算
8. 引用不存在的变量
9. 引用空闲堆块中的数据
10. 引起内存泄露
定义:硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间
虚拟内存是对主存的一个抽象
虚拟内存通过使用虚拟寻址引用主存
虚拟内存三个重要能力
主存看成一个存储在磁盘上的地址空间的高速缓存,高效使用主存
为每个进程提供了一致的地址空间,简化了内存管理/进程共享主存资源的机制
保护了每个进程的地址空间不被其他进程破坏
虚拟内存重要原因
虚拟内存是核心的
涉及硬件异常
涉及汇编器
涉及链接器
涉及加载器
涉及共享对象
涉及文件和进程
虚拟内存是强大的
虚拟内存是危险的
本章内容
虚拟内存如何工作的
应用程序如何管理和使用虚拟内存
动态内存分配
本章主要概念
内存管理单元
地址空间
虚拟页
物理页/页帧
页表条目(PT)
页表基址寄存器(PTBR)
虚拟页号
虚拟页偏移量
物理页偏移量
页表条目地址(PTEA)
翻译后备缓冲器 TLB
多级页表
片(chunk)
交换文件/交换空间/交换区域
共享对象/共享区域
私有对象/私有区域
写时复制技术
动态内存分配(器)
函数
fork
execve
munmap
malloc
free
隐式分配器/垃圾收集器
垃圾收集
空闲块
程序间的交互和通信
第十章 系统级 I/O
1. Unix I/O
1. Unix I/O 概念
将设备优雅地映射为文件的方式
允许 Linux 内核引用一个简单、低级的应用接口
Unix I/O 模型是在操作系统内核中实现的
打开文件
一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备,内核返回描述符表示
Linux shell 创建的每个进程开始时都有三个打开的文件
描述符
标准输入【描述符为0】
标准输出【描述符为1】
标准错误【描述符为2】
改变当前文件的路径
读写文件
关闭文件
2. 文件
文件类型
普通文件
文本文件
二进制文件
目录
一组链接的文件
套接字(socket)
与另一个进程跨网络通信的文件
网络 I/O 文件
目录层次结构
当前工作目录
绝对路径名
相对路径名
3. 打开和关闭文件
open
close
4. 读和写文件
EOF(end of file) 符号
read
write
不足值:当实际 read 和 write 传输的字节要比应用程序要求的少
5. 用 RIO 包健壮地读写
Robust I/O 健壮的I/O
自动处理不足值
网络 I/O【反复执行读写直到传输完所有请求数据】
RIO的无缓冲的输入输出函数
rio_readn
rio_writen
RIO的带缓冲的输入函数
rio_readlineb【文本】
rio_readinitb
rio_readnb
6. 读取文件元数据
stat
fstat
lseek
7. 读取目录内容
opendir
readdir
closedir
8. 共享文件
描述符表【每个进程一个表】
文件表【所有进程共享】
文件位置
v-node 指针
v-node 表【所有进程共享】
文件访问
文件大小
9. I/O 重定向
Linux shell 提供了I/O 重定向操作符,允许用户将磁盘文件和标准输入输出联系起来
dup2
10. 标准 I/O
C 语言定义了一组高级输入输出,为程序员提供了 Unix I/O 的较高级别的替代
以 f 开头,如 fopen
fopen
fdopen
fread
fwrite
fscanf
11. 综合:我该使用哪些IO函数?
Unix I/O 函数【通过系统调用使用】
scanf 【文本】
printf
标准 I/O 函数
尽可能使用
RIO 函数
网络套字节I/O
为什么学系统级I/O
有助于理解其他系统概念
别无选择
系统级I/O概念
I/O 是在【主存】和外部设备(磁盘、终端和网络)之间复制数据的过程
输入操作是从I/O设备复制数据到【主存】
输出操作是从【主存】复制数据到I/O设备
第十一章 网络编程
1. 客户端-服务器编程模型
一个应用是一个服务器进程和一个或多个客户端进程组成
服务器管理的是资源
客户端和服务器是进程,而不是主机
客户端-服务器【事务】
客户端向服务器发起一个请求,一个事务
服务器接收请求,解释它,并以适当的方式操作它的资源
服务器给客户端发送一个响应,并等待下一个请求
客户端收到响应并处理它
客户端-服务器【事务】与数据库事务不是一个概念
2. 网络
对主机而言,网络是又一种 I/O 设备
局域网 LAN(Local Area Network)【以太网 Ethernet】
集成器
网桥
段位 Frame 帧
头部 Header
数据位 payload 有效载荷
广域网 WAN(Wide-Area Network)【Internet】
路由器
互联网
【连接】完全不兼容的广域网和局域网
套字节接口和Unix I/O 函数来通信【系统调用】
硬件接口【中断】
协议软件
命名机制
互联网网络地址 Internet address
传输机制
3. 全球 IP 因特网
最著名和最成功的互联网实现
TCP/IP协议(Transmission Control Protocol / Internet Protocol)【传输控制协议/互联网络协议】
TCP/IP 是一个协议族
IP 协议
TCP 协议
UDP 协议
IP 地址【32位】
因特网域名
层次结构
一级域名
二级域名
DNS 域名系统【主机条目结构】
因特网连接
地址:端口【IP:Port】
4. 套字节接口
套字节接口是一组函数,它们和 Unix I/O 函数结合起来,用以创建网络应用
套字节地址结构
从 Linux 内核角度来讲,一个套字节就是通信的一个端点
从 Linux 程序角度来讲,套字节就是一个有相应描述符的打开文件
socket 函数
创建一个套字节描述符
connect 函数
建立连接
bind 函数
服务器套字节地址【addr】和套字节描述符【sockfd】连接起来
listen 函数
服务器等待来自客户端连接的被动实现
accept 函数
服务器等待来自客户端的连接请求
主机和服务的转换
getaddrinfo【主机名、主机地址、服务名和端口号转化为套字节地址结构】
getnameinfo【套字节地址结构转换为主机和服务器名】
套接字接口的辅助函数
open_clientfd 函数【客户端与服务器建立连接】【封装函数】
getaddrinfo
socket
connect
open_listenfd 函数【服务器创建一个监听描述符,准备好接受连接请求】【封装函数】
bind
listen
5. Web 服务器
Web 基础
Web 客户端和服务器之间的交互用的是一个基于文本的应用级协议 HTTP
HTTP Hypertext Transfer Protocol 超文本传输协议
HTTP 是一个简单的协议
Web 语言HTML Hypertext Markup Language
Web 内容
内容是 MIME 类型相关的字节序列
text/html
text/plain
MIME Multipurpose Internet Mail Extendsions
Web 服务器提供内容方式
静态内容【静态服务器】
动态内容【动态服务器】
URL Universal Resource Locator 通用资源定位符
HTTP 事务
1. HTTP 请求
请求行 request line
请求报头 request header
2. HTTP 响应
响应行 response line
version
status-code
status-message
响应报头 response header
content-Type
content-Length
响应主体 response body
客户端-服务器模式
因特网
IP地址【32位】
域名
连接通信
客服端和服务器通过套字节接口建立连接
Web 服务器使用 HTTP协议通信
第十二章 并发编程
1. 基于进程地并发编程
fork 父子进程【共享文件表】
共享数据困难
进程和IPC开销高【显式IPC机制】
2. 基于 I/O 多路复用的并发编程
基于IO多路复用的并发编程【select】
IO多路复用技术的优势
事件驱动程序【event-driven】
逻辑流模型化为状态机
3. 基于线程的并发编程
线程上下文
线程ID
通用目的寄存器
基于线程的并发服务器
引入竞争
内存泄露
4. 多线程程序中的共享变量
线程内存模型 JMM
将变量映射到内存
共享变量
5. 用信号量同步线程
信号量
用于进程间传递信息的一个整数值
P操作 Test操作
V操作 add操作
使用信号量来实现互斥
二元信号量【互斥锁】
计数信号量
利用信号量来调度共享资源
生产者-消费者问题
读者-写者问题
综合:基于预线程化的并发服务器
6. 其他并发问题
线程不安全函数
不保护共享变量的函数
保持跨越多个调用的状态的函数
返回指向静态变量的指针的函数
调用线程不安全的函数
可重入性函数
线程安全函数
不引用任何共享数据
竞争
死锁
并发应用级作用
访问慢速 I/O 设备
与人交互
通过推迟工作以降低延迟
服务多个网络客户端
在多核机器上进行并行计算
并发程序方法
每个逻辑流是一个进程,由内核来调用
内核调用
独立虚拟地址空间
进程间通信 IPC interprocess communication
I/O 多路复用
共享同一个地址空间【虚拟地址空间】
运行在单一进程上下文中的逻辑流,由内核调用
共享同一个虚拟地址空间
0 条评论
回复 删除
下一页