一、信息就是位+上下文
1.计算机中信息的存储
程序的生命周期是从一个源文件开始的,例如使用C语言编写的.c类型的文件。源程序本质上也就是一个个由值0和1组成的位(也称为比特)序列。同时每8个比特组织在一起,称为字节。每个字节表示程序中的某些文本字符。
2.计算机中信息的表示
大部分现代计算机都使用 ASCII 标准来表示文本字符,这种方式其实也就是使用一个唯一的单字节大小的整数值来表示每个字符。

此处需要我们特别注意的是,每个文本行都是以一个看不见的换行符’\n’结束的,他所对应的整数值为10,对于像.c文件这种只有ASCII的文件称为文本文件,而其他所有的文件都称为二进制文件。
上述例子给我们传达了一个重要的基本思想:在计算机系统中的所有信息,包括 磁盘文件、内存中的程序、内存中存放的用户数据以及网络上的数据都是通过一串比特表示的。区分他们的唯一办法就是读到这些对象时候的上下文。比如在不同的上下文中,一个同样的字节可能表示一个整数、浮点数、字符串或者机器指令。
二、程序的翻译
为了使得.c文件能够在计算机上运行,必须将每条C语句逐一翻译成低级的 机器语言指令,并按照一种称为 可执行目标程序的格式打好包,以二进制的方式存放起来。目标程序称为可执行目标文件。而上述转化过程依赖于编译器的工作,编译器会从源文件读取.c文件。其过程如下:

执行上述四个阶段的程序分别为:预处理器,编译器,汇编器和链接器。他们一起构成了编译系统。
而依据主要功能的不同,我们将.c文件到机器码的整个过程划分为如下四个阶段:
- 预处理阶段:预处理器(以C语言为例)会根据#开头的文件(我们通称为头文件,例如stdio.h),读取相应的文件,并在源代码中插入相应的代码,生成新的.i文件。
- 编译阶段:编译器将.i的文本文件翻译为.s的文本文件,其中包含的是汇编语言的程序。汇编语言是非常有用的,对于不同的高级语言而言,实现相同功能的汇编语言具有统一的格式。
- 汇编阶段:汇编器将上述.s文件翻译成机器语言指令,并将这些指令打包,存放在一个称为可重定位目标程序的程序中。得到.o的一种二进制文件。
- 链接阶段:将已经编译好的库中的.o文件插入到代码中的相应位置,例如调用标准库中的printf,链接完成后即得到可执行文件,它可以被加载到内存中并由系统执行。
上述了解计算机系统对文件的翻译过程能够帮助我们优化程序的性能,理解在连接时候产生的错误,更好地避免安全漏洞,写出更好的程序。
三、计算机系统的工作
1.系统的硬件组成
对于一个典型的计算机系统而言,其包括以下部分:总线、IO设备、主存、处理器。四个主要模块,接下来我们对其进行更进一步的说明:

总线
贯穿于整个计算机系统的是一组电子管道,我们称作总线。总线负责 携带信息字节并在各个部件之间传递。通常总线被设计成传送固定字长的字节快,也就是字。字中的字节数(字长)是一个系统的基本参数,在各个计算机系统中稍有区别。现代计算机系统的字长大多为4个字节(32位)或8个字节(64位)。
IO设备
顾名思义,IO设备时input/ouput设备的简称,其设备是系统与外界联系的通道。如上图中我们的IO设备包括鼠标、键盘、显示器以及磁盘。 每个IO设备都通过控制器或者适配器与总线相连。控制器是IO设备本身或者主板上的芯片组,而适配器是插在主板上的卡。
主存
主存是一个临时存储设备,在执行程序之时,用来存放程序和程序处理的数据。从物理组成上来说,主存是由一组动态随机存储器(DRAM)组成的,从逻辑上来说存储器是一个线性的字节数组,每个字节都具有其唯一的数组索引地址。
处理器
中央处理单元(CPU),简称处理器,是解释或执行存储在主存中指令的引擎。处理器的河西是一个大小为一个字的储存设备(寄存器),称为程序计数器PC。在任何时刻PC都指向主存中的某条机器语言指令。这整个过程都是由指令集架构决定的,处理器从程序计数器指向的内存处读取指令,并解释指令中的位,并执行指令中的位,而后转向下一条指令。
这样简单操作围绕着主存、寄存器文件和算数/逻辑单元进行。寄存器文件时一个效电存储设备,由一些单个字长的寄存器组成,每个寄存器都有其唯一名字。
CPU在指令下的操作:
- 加载:从主存复制一个字节或者一个字到寄存器,以覆盖原来的内容。
- 存储:把寄存器赋值一个字节或者一个字到主存的某个位置,以覆盖寄存器原来的内容。
- 操作:把两个寄存器中的内容复制到ALU,ALU对这两个字做算数运算并将结果放到一个寄存器中,以覆盖原来的内容。
- 跳转:从指令本省抽取一个字,并将这个字复制到程序计数器PC中,以覆盖PC中原来的值。
程序的运行过程
计算机中程序执行流程如下图:
- 我们通过IO设备与计算机进行交互,当我们输入程序执行命令的时候计算机通过总线将每一个字符注意存入寄存器,再将其放入内存中。

- 接着当我们输入回车键时,我们完成命令的输入。计算机将数据从磁盘加载到主存,过程如下:

- 一旦完成上述加载过程,处理器就开始执行程序指令,当指令完成执行后,寄存器再通过总线将文件复制到显示设备,最终显示再屏幕上,过程如下:

四、高速缓存
对于某个程序而言,其首先是存储再磁盘上的;当程序加载时候,他被复制到主存;程序运行时,指令又从主存复制到处理器。这些诸多的复制过程极大地降低了计算机的工作效率,增大了计算机工作的负担,为此我们设计了高速缓存来解决这一问题。
根据机械原理,较大的存储设备要比较小的存储设备运行得慢,而快速设备的造假远远高于低俗设备。具体说来寄存器中中只能存储几百字节的信息,而在主存中则可存放几十亿个字节的信息。(此处可以参考数据结构B树的有关内容。)
正对这种不平衡,我们设计了高速缓存机制来处理这个问题。

五、设备的层次与存储结构
对于大量数据的处理,我们往往每次只使用其中的一小部分数据。而且通常在某一段时间内,我们常用的数据是固定的,于是为了解决处理器与较大速度较慢的存储器之间速度与容量的矛盾,我们通常采用分层机制来存储计算机中的数据。

存储器层次结构的主要思想是上一层的存储器作为低一层存储器的高速缓存。因此, 寄存器文件就是 L1 的高速缓存,L1 是 L2 的高速缓存,L2 是 L3 的高速缓存,L3 是主存 的高速缓存,而主存又是磁盘的高速缓存。在某些具有分布式文件系统的网络系统中,本 地磁盘就是存储在其他系统中磁盘上的数据的高速缓存。
六、操作系统管理硬件
回到.c程序的例子,在shell加载和运行程序时,底层的操作系统帮助我们完成了指令与硬件的交互。我们可以把操作系统看作是上层应用程序域硬件之间插入的一层软件。
操作系统有两个基本功能:
- 方式硬件呗时空的应用程序滥用;
- 向应用程序提供简单一致的机制来控制复杂而低级的硬件设备;
进程
进程是操作系统对正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程,而每个进程都好像在独占得使用硬件。而 并发运行则是说一个进程的指令和另外一个进程的指令是交错执行的。在大多是系统中,需要运行的简称数目是远多于CPU数目的。
CPU为了使得在某一个时刻看上去只执行一个程序,使用的是通过处理器在进程中切换来实现的。操作系统实现这种交错的机制称为 上下文切换。

从一个进程到另外一个进程的切换时有内核管理的,内核时操作系统中代码常驻部分。
线程
在了解了进程后,我们来说明线程的概念。一个进程实际上可以分为多个线程,每个线程都运行在进程的上下文中,并享有同样的代码和全局数据。线程一般来说比进程更加高效。
虚拟内存
虚拟内存是计算机中的一个抽象概念,他为每个进程提供了一个加相,即每个进程都在独占使用主存。每个进程看到的内存是一致的,我们称为虚拟地址空间。(但是实际上是不同的)

接下来我们来逐一介绍虚拟内存中的各个部分。
- 程序和数据:对于所有程序来说,代码都是从统一固定地址开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是按照可执行文件初始化的。
- 堆:代码和数据区后紧随着的是运行时堆。代码和数据区在进程以开始运行时就被指定了大小。而堆可以动态的扩展和收缩。
- 共享库:地址库大约中间的位置有一块是用来存放像C标准库和数学库这样的共享代码和数据的区域。
- 栈:位于用户虚拟地址空间顶部的是用户占,编译器用顶部的栈来实现程序中的函数调用。栈也可以动态得扩展和收缩。每此次调用函数时,函数栈就会增长,反之从函数返回时,栈就会收缩。
- 内核虚拟内存:地址空间顶部的区域是为内核保存的。不允许程序读写这个区域的内容或者是直接调用相应的函数。相反这部分函数的调用,必须依赖操作系统的内核。
文件
文件的本质就是字节序列。每个IO设备本质上在计算机中都可以看作是一个独立的文件。系统中的所有输入输出都是通过使用与小组称为Unix I/O的系统函数调用读写文件来实现的。
网络通信
现代的计算机之间并非孤立的个体,不同计算机之间可以通过网络连接在一起。网络通常可以视作计算机的一个IO接口,当系统从主存复制一串字节到网络适配器时,数据流经网络到达另外一台机器,而非本地的磁盘驱动器。
重要主题
本章中我们概述了计算机系统中各个重要部分的组成与作用。其中有一个十分重要的观点 计算机系统是硬件和软件互相交织的结合体。他们必须通过协同工作达到最终目的。
Amdahl定律
Amdahl定律描述了计算机系统部分性能提升与整体性能提升之间的关系。该定律的只要思想是:当我们堆系统的某个部分加速时其堆系统整体性能的影响取决于该部分的重要和加速程度。假定系统执行某应用程序需要的时间为$T_{old}$,假设系统某部分占全体的重要性为$\alpha$,而该部分性能提升为$k$.即该部分初始所需时间为:$\alpha T_{old}$,现在所需时间为$\frac{\alpha T_{old}}{k}$.因此此时,总的执行时间为:
那么加速比为:
通过Amdahl定律,我们引出了一个在计算机领域十分重要的概念:相对性能
性能提升最好的表示方法就是通过使用比例的形式$\frac{T_{old}}{T_{new}}$,并且使用X来表示比例,因此2.2X读作2.2倍。
并发和并行
并发是指一个同时具有多个活动的系统,并行是指用并发来使一个系统运行得更快。在此,我们按照系统层次结构中由高到低的顺序介绍三个层次:
- 线程级并发:构建在进程这个抽象概念之上,我们能够设计出同时又多个程序执行的系统,这就是所谓的并发。使用线程,我们甚至能够在一个进程中执行多个控制流。事实上的并发是通过是计算机在不同进程中快速切换实现的。但是想在的多核处理器和超线程的出现意味着能够在不同CPU上处理不同的进程从而实现正真意义上的并发。

如上图所示是多核计算机系统的组织结构图,我们可以看出不同的CPU配有各自的L1和L2高速缓存。而共享更高层次的L3告诉缓存。
超线程,也称为同时多线程,是一项允许一个CPU执行多个控制流的级数,它涉及CPU某些硬件的多个备份,比如程序计数器和寄存器文件,而其他的硬件部分只有一份,比如执行浮点算术运算的单元。常规的处理器需要大约 20 000 个时钟周期做不同线程间的转换,而超线程的处理器可以在单个周期的基础上决定 要执行哪一个线程。这使得 CPU 能够更好地利用它的处理资源。
对于上述两种改进的意义:多处理器的使用可以从两方面提高系统性能。首先,它减少了在执行多个任务时模拟 并发的需要。正如前面提到的,即使是只有一个用户使用的个人计算机也需要并发地执行 多个活动。其次,它可以使应用程序运行得更快,当然,这必须要求程序是以多线程方式 来书写的,这些线程可以并行地高效执行。
指令级的并行
在较低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级的滨兴。简单来说指令级别的并行是通过不同指令需要使用不同的部分来进行操作,类似于流水线。单指令、多数据的并行
在最低层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并行执行的操作,这种方式称为单指令、多数据,即SIMD并行。
计算机中的抽象
计算机中的抽象是一个十分重要的概念。在处理器中指令集架构提供了对实际处理器邮件的抽象,使用这个抽象,机器代码运行表现得就像在一个一次只执行一条指令的处理器上。底层硬件远比描述复杂。

在学习操作系统时,我们介绍了三个抽象:文件是对 I/O设备的抽象,虚拟内存是对 程序存储器的抽象,而进程是对一个正在运行的程序的抽象。我们再增加一个新的抽象:虚拟机,它提供对整个计算机的抽象,包括操作系统、处理器和程序。