1.计算机系统漫游

1.1 信息就是 位 + 上下文

  1. 计算机系统是由硬件和系统软件组成的,它们共同工作来运行应用程序
  2. 安全漏洞很有可能由存储缓冲区溢出错误引起
  3. 计算机系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串 bit 表示的。区分不同数据对象的唯一办法就是读到这些数据对象时的上下文

1.2 程序被其他程序翻译成不同的格式

编译系统:源程序 -> 预处理器 -> 编译器 -> 汇编器 -> 连接器

预处理器:处理导入引用内容等,如 #include<stdio.h>,得到的文件通常以 .i 作为文件扩展名  
编译器:把 .i 文件翻译为 .s 文件,.s 文件是一个汇编语言程序
汇编阶段:汇编器(as)把 .s 文件翻译成机器语言指令,把这些指令打包成一种叫做  
         可重定位目标程序(relocatable program),得到的文件以 .o 作为扩展名,  
         .o 文件是一个二进制文件,native code  
链接阶段:处理系统函数库,将多个 .o 文件合成一个可执行目标文件,如 printf() 函数,  
         该文件可以被加载到内存中由系统执行  

compiler-system

GNU(GNU'S Not Unix)是一个免税的慈善项目,该项目的目标是开发出一个完整的类 Unix的系统,  
其源代码能够不受限制的被修改和传播。虽然 GNU 并没有开放出内核,但是其提供的工具为 Linux  
内核提供了环境,包括:EMACS 编辑器、GCC 编译器、GDB 调试器、汇编器、链接器、处理二进制文件  
的工具以及其他一些部件。

1.4 处理器读并解释存储在内存中的指令

一个典型的计算机系统的硬件组成:computer-hardware-component

  1. 总线
    贯穿整个系统的是一组电子管道,称作总线,它携带信息字节并负责在各个部件间传递。  
    通常总线被设计成传送定长的字节块,也就是字(word)。字中的字节数(即字长)  
    是一个基本的系统参数,比如 32 位系统字长就是 4bytes,64 位系统字长是 8bytes。
  2. I/O 设备
    I/O(输入/输出)设备是系统与外部世界的联系通道,比如作为用户输入的键盘和鼠标、  
    作为用户输出的显示器,以及用于长期存储数据和程序的磁盘。每个 I/O 设备都通过  
    一个 I/O 控制器/适配器与 I/O 总线相连。
  3. 主存
    主存是一个临时存储设备,在 CPU 执行程序时,用来存放程序和程序处理的数据。  
    从物理上来说,主存是由一组动态随机存储器(DRAM)芯片组成的。  
    从逻辑上来说,存储器是一个线性的字节数组,每个字节都有其唯一的地址(数组索引),  
    这些地址从 0 开始。一般来说,组成程序的每条机器指令都由不同数量的字节组成。
  4. 处理器
    CPU 是解释/执行存储在主存中指令的引擎。处理器的核心是一个大小为一个字的存储设备(或寄存器),  
    称为程序计数器(PC)。  
    在任何时刻,PC 都执行主存中的某条机器语言指令(即含有该条指令的地址)。  
    CPU 看上去是按照一个非常简单的指令执行模型来操作的,这个模型是由指令集架构来决定的。  
    在这个模型中,指令按照严格的顺序执行,而执行一条指令包含执行一系列的步骤。  
    处理器从 PC 指向的内存处读取指令,解释指令中的位,执行该指令指示的简单操作,然后更新 PC,  
    使其指向下一套指令。这样的简单操作并不多,他们围绕着主存、寄存器文件(register file)和  
    算术/逻辑单元(ALU)进行。  
    寄存器文件是一个小的存储设备,由一些单个字长的寄存器组成,每个寄存器都有唯一的名字。  
    ALU 计算新的数据和地址值。  
    CPU 看上去是它的指令集架构的简单实现,但是实际上现代处理器使用了非常复杂的机制来加速程序的执行。  
    指令集架构描述的是每条机器代码指令的效果;而 CPU 的微体系描述的是处理器实际上是如何实现的。  

1.5 高速缓存至关重要

hello 程序的 native code 最初是存放在磁盘上,当程序加载时,他们被复制到主存;  
当 CPU 运行程序时,native code 又从主存复制到 CPU 的寄存器。  
相似的,数据串"hello, world\n"开始时在磁盘上,然后被复制到主存,最后从主存上复制到显示器。  
这些复制在程序员角度就是开销,减慢了程序“真正”的工作。

CPU 的速度和主存之间的差距在持续增大,针对这种差异系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory),来存放近期可能会需要的信息,如 L1/L2/L3 缓存,L1/L2缓存是用一种叫做静态随机访问存储器(SRAM)的硬件技术实现的。系统可以获得一个很大的存储器,同时访问速度也很快,这是利用了高速缓存的局部性原理。

cache-memory

意识到高速缓存存储器的存在,可以让你的程序能够利用高速缓存将程序的性能提高一个数量级,比如 CPU cache line 的应用(64 way * 64 bytes/way = 4096 bytes)。

1.6 存储设备形成层次结构

memory-hierrachy

存储器层次结构的思想是上一层的存储器作为低一层存储器的高速缓存,如主存是磁盘的高速缓存,磁盘是网盘的高速缓存。同利用高速缓存来提高程序性能一样,同样可以利用存储器层次结构来提高程序性能。

1.7 操作系统管理软件

os-abstract

1.7.1 进程

操作系统通过对硬件进行抽象(进程、虚拟内存 、文件),来充当应用程序和底层硬件的交互媒介。
文件是 I/O 设备的抽象表示,虚拟内存是对主存和磁盘 I/O 设备的抽象表示,
进程则是对 CPU、主存和 I/O 设备的抽象表示,进程是计算机科学中最重要和最成功的概念之一

  1. 进程是操作系统对一个正在运行的程序的一种抽象,实现进程这个抽象概念需要低级硬件和操作系统软件之间紧密合作
  2. 并发运行:一个进程的指令和另一个进程的指令是交错执行的,CPU 实现这种交错执行的机制称为上下文切换
  3. 上下文:操作系统保持跟踪进程运行所需的所有状态信息
  4. 上下文切换是由操作系统内核(kernel)管理端 ,kernel 是操作系统常驻主存的一部分。应用程序执行系统调用(system call)指令,将运行控制权传递给内核,内核执行完后再返回应用程序。

kernel 不是一个独立的进程,相反,它是系统管理全部进程所用代码合数据结构的集合

1.7.2 线程

尽管通常我们认为一个进程只有单一的控制流,但是在现代操作系统中,一个进程实际上  
可以由多个称为线程的执行单一组成。每个线程都运行在进程的上下文中,并共享同样的  
代码合全局数据。线程称为越来越重要的编程模型。

1.7.3 虚拟内存

虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地使用主存。
每个进程看到的内存都是一致的,称为虚拟地址空间。

process-virtual-memory

在 Linux 中,地址空间最上面的区域是保留给操作系统中的代码合数据点,这对所有进程来说都是一样。
地址空间的底部区域存放用户进程定义的代码合数据。

每个进程看到的虚拟地址空间由大量准确定义的区构成,地址从低到高分别是:

  1. 程序代码和数据:native code,这个区的代销是在进程运行时就被指定了大小
  2. 堆:运行时堆,当调用 malloc 和 free 时对可以动态扩展收缩
  3. 共享库:存放如 C 标准库和数学库这样的代码合数据
  4. 栈:用户栈,用来实现函数调用,可动态扩展收缩
  5. 内核虚拟内存:为内核保留的,不允许应用程序读写该区域,必须调用内核来执行操作

1.7.4 文件

文件就是字节序列,仅此而已。(文件就是可以进行 I/O 的字节序列)

每个 I/O 设备,包括磁盘、键盘、显示器,设置网络,都可以看成是文件。  
系统中所有的输入输出都是通过使用一组称为 Unix I/O 的系统函数调用来实现读写文件的。

文件是一个简单精致而强大的概念,它像应用程序提供了一个统一的视图,来看待系统中可能含有的所有各种各样的 I/O 设备。

1.8 系统之间利用网络通信

从一个单独的系统来看,网络可视为一个 I/O 设备。当系统从主存复制一串字节到网络适配器时,数据流经过网络到达另一台机器,而不是说到达本地磁盘驱动器。相似地,系统可以读取从其他机器发送来的数据,并把数据复制到自己的主存。
internet-io

1.9 重要主题

系统是硬件和系统软件互相交织的几何体,他们必须共同协作以达到运行应用程序的最终目的。

1.9.1 Amdahl 定律

当我们对系统的某个部分加速时,其对系统整体性能的影响取决于该部分的重要性和加速程序。

1.9.2 并发和并行

并发(concurrency)是一个通用的概念,指一个同事具有多个活动的系统;
并行(parallelism)指的是用并发来使一个系统运行得更快

  1. 线程级并发(多核架构、超线程(同时多线程))
  2. 指令集并行(CPU Pipeline)
  3. 单指令、多数据并行(允许一条指令产生多个可以并行执行的操作)

1.9.3 计算机系统中抽象的重要性

抽象的使用是计算机科学中最为重要的概念之一

在处理器里,指令集架构提供了实际处理器硬件的抽象,使得程序表现得就好像运行在一个一次只执行一条指令的处理器上。

computer-abstract

计算机系统提供的一些抽象。  
计算机系统中的一个重大课题就是提供不同层次的抽象表示,来隐藏实际出现的复杂性。
  1. 文件是对 I/O 设备的抽象
  2. 虚拟内存是对主存和磁盘的抽象
  3. 进程是对一个正在运行的程序的抽象(处理器、主存和 I/O 设备)
  4. 虚拟机是对整个计算机的抽象,包括操作系统、处理器和程序