操作系统两个基本功能
- 防止硬件被失控的应用程序滥用
- 向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。
大端法和小端法
- 大端法:高地址高字节
- 小端法:高地址低字节
- IBM和Oracle大多数机器是按大端模式操作
- Intel兼容处理器,使用小端法
- 较新的微处理器(ARM)是双端法,(可设置,默认是小段模式),但安卓和IOS操作系统都只能运行在小端模式下。
原码,反码,补码
- 正数的原码,反码,补码都一样
- 负数的原码,反码将原码按位取反,补码将反码+1
机器级编程的两种抽象
- 由指令集体系结构或指令集架构来定义机器级程序的格式和行为,它定义了处理器状态,指令的格式,以及每条指令对状态的影响。
- 机器级程序使用的内存地址是虚拟地址,提供的内核模型,看上去是一个非常大的字节数组。
汇编
数据类型 | 汇编代码后缀 |
---|---|
short | w |
char | b |
intt | l |
long | q |
char * | q |
float | s |
double | l |
操作数的可能性,三种类型
- 立即数
- 寄存器
- 内存引用
立即数 | $Imm | Imm | 立即数寻址 |
---|---|---|---|
寄存器 | ra | R[ra] | 寄存器地址 |
MOV指令
MOV | S,D | D<-S | |
---|---|---|---|
movb | 传送字节 | ||
movw | 传送字 | ||
movl | 传送双字节 | ||
movq | 传送四字节 | ||
movabsq | I,R | R<-I | 传送绝对的四字节 |
压栈和入栈
pushq | s | 将四字压入栈中 |
---|---|---|
popq | D | 将四字弹出栈 |
- 栈地址由高到低增长。
- 加载有效地址指令leaq,实际上是movq指令的变形。
CMP和TEST
CMP | S1,S2 | S2-S1 | 比较 |
---|---|---|---|
TEST | S1,S2 | S1&S2 | 测试 |
- test,两个操作数一样的,用来检测操作数是(负数,0,正数)
CALL和REAT
- call .调用函数
- reat 返回函数
GOTO
- 跳转指令:jump(goto)
寄存器组是唯一被所有过程共享的资源
调用者保存恢复(概念)
对抗缓冲区溢出攻击
- 栈随机化,栈位置在程序每次运行时都有变化
- 栈破坏检测,检测栈何时已被破坏,(GCC金丝雀)
- 限制可执行代码区域,哪些内存区域能够存放可执行代码
程序性能优化
循环展开是一种程序变换,通过增加每次迭代计算的元素和数量,减少循环的迭代次数。
- 减少了不直接有助于程序结果的操作和数量
- 提供了一些方法有助于进一步变化代码,减少整个计算中关键路径上的操作数量
条件分支
- 投机执行的处理器
- 执行预测的分支目标处的指令,避免修改任何实际的寄存器或内存位置,直到确定了实际的结果(正确就“提交”,错误就“丢弃”)
优化程序性能的基本策略
- 高级设计,选择适当算法和数据结构
- 基本编码原则
- 消除连续函数调用
- 消除不必要的内存引用
- 低级优化,结构化代码以利用硬件功能(如展开循环)
局部性基本属性
局部性原理:倾向于引用邻近于其他最近引用过的数据项的数据项,或最近引用过的数据项本身,这种倾向性,称为局部性原理。
- 局部性两种不同形式
- 时间局部性
- 空间局部性
量化评价原则
- 重复引用相同变量
- 对具有步长为k的引用模式的程序,步长越小,空间局部性越好。
- 循环体越小,迭代次数越多
编写高速缓存友好的代码的重要问题
- 对局部变量的反复引用是好的,因为编译器能够将他们缓存在寄存器文件中。
- 步长为1的引用模式是好的,因为存储器层次结构中所有层次上的缓存都是将数据存储为连续的块(空间局部性)
异常控制流(EFC)
- 理解EFC将帮助你理解重要的系统概念,是操作系统用来实现I/O,进程和虚拟内存的基本机制。
- 理解EFC将帮助你理解应用程序是如何与操作系统交互的,应用程序通过使用一个叫陷阱或系统调用的EFC形式,向操作系统请求服务
- 有助于编写有趣的新应用程序
- 帮助你理解并发
- 理解软件异常如何工作
异常就是控制流的一种形式,一部分由硬件实现,一部分由操作系统实现,异常就是控制流中的突变,用来响应处理器状态中的某些变化。
异常类似过程调用,但是有一些不同之处
- 过程调用,跳转处理程序前将返回地址压入栈中,根据异常类型,返回地址要么是当前指令,要么是下一条指令。
- 处理器也把一些额外的处理器状态压入栈中,程序返回时,重新开始执行
- 若控制从用户程序转移到内核所有这些项目都被压到内核中,而不是压到用户栈中。
- 异常处理程序运行在内核模型下,意味着他们对所有的系统资源都有完全的访问权限。
异常类别
中断 | I/O设备信号 | 异步 | 总返回到下一条指令 |
---|---|---|---|
陷阱 | 有意异常 | 同步 | 总返回到下一条指令 |
故障 | 潜在可恢复错误 | 同步 | 可能返回到当前指令 |
终止 | 不可恢复错误 | 同步 | 不会返回 |
X86-64系统
系统调用是通过一条称为syscall的陷阱指令来提供的。
上下文
系统中的每个程序都运行在某个进程的上文中,上下文是由程序正确运行所需的状态组成。
关注进程提供给应该程序的关键抽象
- 一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器
- 一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用内存系统
并发
- 多个流并发地执行的一般现象称为编发。
一个进程执行它的控制流的一部分的每一时间短也叫做时间片。
多任务也叫做时间分片。 - 如果两个流并发地运行在不同的处理器核或计算机上,我们称它们为并行流,它们并行地运行,且并行地执行。
上下文切换和信号
- 操作系统内核使用一种称为上下文切换的较高层次的异常控制流来实现多任务。
- 一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件,每种信号类型都对应于某种系统事件。
安全的信号处理(编写处理程序的原则)
- G0,处理程序需尽可能简单。
- G1,处理程序中只调用异步信号安全的函数(1)可重入,2)不能被信号处理程序中断),
- G2,保存和恢复errno
- G3,阻塞所有的信号,保护对共享安全数据结构的访问
- G4,用volatile申明全局变量
- G5,用sig_atomic_t申明标志
非本地跳转
用户级异常控制流形式,称为非本地跳转,它将控制直接从一个函数转移到另一个当前正在执行的函数,而不需经过正常的调用-返回程序(setjmp,longjmp)。
虚拟内存三个重要能力
- 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动空间,并根据需要在磁盘和主存之间来回传送数据,通过这种形式,它高效实用主存。
- 它为每个进程提供了一致的地址空间,从而简化了内存管理。
- 它保护了每个进程的地址空间,不被其他进程破坏。
虚拟内存它是沉默地自动地工作的,不需要应用程序员任何干涉。
- 虚拟内存是核心的
- 虚拟内存是强大的
- 虚拟内存是危险的
CPU芯片上叫做内存管理单元的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址。
物理内存被分割为物理页(pp),大小也为p字节(物理页也被称为页帧(page frame))
虚拟页面的集合都分为三个不相交的子集
- 未分配的
- 缓存的
- 为缓存的
缓存
- 表示位于CPU和主存之间的L1,L2和L3高速缓存
- 并且用术语DRAM缓存来表示虚拟内存系统的缓存,它在主存中缓存虚拟页
- 页表(物理内存)将虚拟页映射到物理页(数据结构)
抖动
如果工作集的大小超出了物理内存的大小,那么程序将产生一种不幸的状态,称为抖动
内存映射
Linux将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射。
(Linux文件系统中的普通文件,匿名文件)
动态内存分配
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。
分配器将堆视为一组不同大小的块的集合来维护。每个块就是一连续的虚拟内存片,要么是已分配的,要么是空闲的,已分配的块显示地保留为供应用程序使用,空闲块可用来分配,空闲块保持空闲,直到它显示地被应用所支配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么应用程序显示地执行,要么是内存分配器自身隐式执行。
- 显式内存分配器:malloc,free
- 隐式内存分配器:垃圾收集器
碎片
当有未使用的内存,但不能用来满足分配请求时,就发生这种现象
(内部碎片,外部碎片)
垃圾收集器
是一种动态内存分配器,它自动释放程序不再需要的已分配块。
垃圾收集器将内存视为一张可达图
- 可达:空闲
- 不可达:垃圾,不可被应用再次调用
网络编程
C/S中基本操作事务
- 客户端要服务时,向服务器发送一个请求,发起一个事务。
- 服务器收到请求后,解释它,并以适当的方式操作它的资源
- 服务器给客户端发送一个响应,并等待下一个请求
- 客户端收到响应并处理
套接字接口socket
套接字接口是一组函数,他们和UNIX的I/O函数结合起来,用以创建网络应用。
并发
使用应用级并发的应用程序称为并发程序,现代操作系统提供了三种基本的构造并发程序的方法
- 进程。用这种方法,每个逻辑控制流都是一个进程,由内核来调度和维护
- I/O多路复用。这种形式并发编程,应用程序在一个进程的上下文中显示地调度它们自己的逻辑控制流
- 线程。线程是运行在一个单一进程上下文中的逻辑流,由内核进行调度,像进程流一样由内核进行调度,而像I/O多路复用流一样共享同一个虚拟地址空间。
I/O多路复用
- I/O多路复用可以用做并发事件驱动程序的基础,在事件驱动程序中,某些事件会导致流向前推进。
- 一般思路是将逻辑流模型转化为状态机
- 一个状态机就是一组状态,输入事件和转移,其中转移是将状态和输入事件映射到状态,每个转移是将一个(输入状态,输入事件)对映射到一个输出状态。
- 自循环是同一输入和输出状态之间的转移