深入理解计算机系统1——计算机系统漫游
计算机系统漫游
计算机系统=硬件+系统软件构成的。
它们共同工作来运行应用程序。系统的具体实现方式随时间变化,但是系统的内在概念却没有改变。
深入了解计算机系统的组件如何影响程序的正确性和性能。
====================================================
信息就是位+上下文
源程序实际上是由0和1组成的位序列。8个位被组织成一组,称为字节。每个字节表示程序中某个文本字符。现代系统都使用ASCII标准来表示文本字符。
源程序以字节序列的方式存储在文件中。每个字节都有一个整数值,每个整数值对应一个文本字符。由ASCII字符构成的文件称为文本文件。所有其他文件都被称为二进制文件。
基本思想:计算机中所有的信息都是由一串位表示的。区分不同数据对象的唯一方法就是读到这些数据对象时的上下文。在不同的上下文中,同一个字节序列可能表示不同的含义。
作为程序员需要了解数字的机器表示方式。
====================================================
程序被其他程序翻译成不同的格式
高级语言程序(能够被人读懂)——(其他程序转换)——>低级机器语言指令——(按照指定格式打包)——>可执行目标文件(也叫做可执行目标文件)(以文件形式存放);
从源文件到可执行目标文件的过程有四个阶段:预处理器、编译器、汇编器、链接器;
预处理器
编译前对源程序hello.c的替换与处理。结果是得到另一个C程序,即hello.i。
编译器
将文本文件hello.i翻译成文本文件hello.s,即汇编语言程序。
汇编器
将hello.s翻译成机器语言指令。把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式。并将结果保存在目标文件hello.o中。hello.o文件是二进制文件,它的字节编码是机器语言指令而不是文本字符,所以用文本编辑器打开的话将会看到一堆乱码。
链接器
例如hello程序中调用了printf函数,它是每个C编译器都会提供的标准C库中的一个函数。printf函数存在于一个名为printf.o的单独的预编译好了的目标文件中。这个文件必须以某种方式合并到我们的hello.o程序中。链接器就是负责处理这种合并的。
GNU项目:开源的,开发出包含Unix操作系统的所有主要部件的环境。(内核除外,Linux项目是独立发展出来的),GNU环境包括:EMACS编辑器、GCC编译器、GDB调试器、汇编器、链接器、处理二进制文件的工具以及其他一些部件。
GCC编译器已经发展成针对不同的语言,不同的机器生成代码。
====================================================
编译系统如何工作
了解编译器的重要的原因:优化程序性能,理解链接时出现的错误,避免安全漏洞;
====================================================
处理器读并解释存储在存储器中的指令
Shell是一种命令行解释器,它输出提示符,等待你输入一个命令行,然后去执行这个命令。如果该命令行的第一个单词不是一个内置的外壳命令,那么外壳将会假设这是一个可执行文件名字,加载并运行这个文件。
典型系统的硬件组成:
总线:被设计成传输定长的字节块,也就是字(word)。字长是一个基本的系统参数。例如32位(4个字节)字长。
I/O设备:系统与外部世界的联系通道。每个I/O设备都通过控制器或者适配器与I/O总线相连。控制器与适配器之间的区别主要在于它们的封装方式。它们的功能都是在I/O总线和I/O设备之间传递信息。适配器是一块插在主板插槽的卡。控制器是置于I/O设备本身的或者系统的主印制电路板上的芯片组。
主存:
主存是一个临时存储设备。在处理器执行程序时,用于存放程序和程序处理的数据。物理上来讲:主存是一组DRAM芯片组。逻辑上来讲:是线性的字节数组,每个字节都有其唯一的地址。
处理器:
CPU,或处理器,解释或执行存储在主存中的指令的引擎。
处理器的核心是:一个字长的存储设备,(或寄存器)。称为程序计数器PC,在任何时刻PC都指向主存中的某条机器语言指令(即PC中存有该指令在主存中的地址)。
一个非常简单的指令执行模型:处理器按照这个模型运作。
这个模型由指令集结构决定。
在整个模型中,执行一条指令按照一系列步骤展开:1、处理器从PC指向的存储器中读取指令;2、解释指令中的位,执行该指令指示的简单操作;3、更新PC,使其指向下一条指令,而这一条指令并不与刚刚执行的指令相邻;
这些操作都是围绕:主存(内存)、寄存器文件(小的存储设备,一些1字长的寄存器组成)、算数/逻辑单元(ALU负责计算新的数据和地址值)进行的。
CPU在指令的要求下可能进行如下操作:
加载:主存->寄存器;
存储:寄存器->主存;
操作:将连个寄存器的内容复制到ALU,ALU对这两个字做算术运算,将结果保存到另一个寄存器中;
跳转:从指令本身抽取一个字,并将这个字复制到程序计数器PC中,以覆盖PC中原来的值。
处理器看上去只是它的指令集结构的简单实现,但是实际上现代处理器用了非常复杂的机制来加速程序的执行。
指令集结构:描述的是每条机器代码指令的效果;-->研究机器代码时考虑的是机器的指令集结构所提供的抽象性;
微体系结构:描述的是处理器实际上是如何实现的;-->处理器实际上是如何实现的
利用DMA技术,数据可以不通过处理器而直接从磁盘到达主存。
====================================================
高速缓存至关重要
系统花了大量的时间把信息从一个地方挪到另一个地方。从程序员角度来看,这实际上就是开销,减缓了程序的“真正”的工作。系统设计者的主要目标就是使这些复制操作尽可能快地完成。
处理器越来越快,但是主存的速度更不上。系统设计者采用了更小、更快的存储设备,告诉缓存存储器(简称高速缓存),作为暂时的集结区域,用于存放处理器近期可能会需要的信息。
三级高速缓存:L1(比L2快5倍)、L2(SRAM比主存快5~10倍)、L3(比主存快,主存属于L4);
L0是寄存器;
利用高速缓存,程序员可以将他们的程序性能提高一个数量级。--->如何利用高速缓存?
====================================================
存储设备形成层次结构
L0:寄存器,最快(但是相应地造价更高,存储空间更小);
L1:L1高速缓存;
L2:L2高速缓存;
L3:L3高速缓存;
L4:主存(DRAM);
L5:本地二级存储(本地磁盘);
L6:远程二级存储(分布式文件系统,Web服务器);
====================================================
操作系统管理硬件
应用程序不直接操作硬件,而是通过操作系统。操作系统提供两大基本功能:
1)防止硬件被失控的应用程序滥用;
2)向应用程序提供简单一致的机制来控制复杂而又通常大相径庭的低级硬件设备;
操作系统实现这两大功能,通过几个基本的抽象概念:进程、虚拟存储器、文件;
抽象表示:
文件是对I/O设备的抽象表示;
虚拟存储器是对主存和磁盘I/O设备的抽象表示;
进程是对处理器、主存和I/O设备的抽象表示;
进程
进程是计算机中最重要和最成功的概念之一;
进程是操作系统对一个正在运行的程序的一种抽象。操作系统保持跟踪进行运行所需的所有状态消息。这种状态,也就是上下文。任何时刻,单处理器系统都只能执行一个进程的代码。当操作系统决定要把控制权从一个进程转移到另一个进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文。然后将控制权转移到新进程上。所以会让用户看上去好像计算机在同时执行多个程序。
实现进程这一抽象概念需要硬件和操作系统软件之间紧密配合。
线程
一个进程实际上可以由多个称为线程的执行单元组成。每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。多线程之间比多进程之间更容易共享数据。线程一般来说比进程更高效。由于网络服务器对并行处理的需求,线程成为一种越来越重要的编程模型。线程是一种使程序运行更快的方法,
虚拟存储器
虚拟存储器是一种抽象概念,它为每个进程提供一种假象,即每个进程都在独占地使用主存。每个进程看到的是一致的存储器,虚拟地址空间。
程序代码的数据 :对于所有进程来说,代码是从同一固定地址开始的,紧接着的是和C全局变量相对应的数据位置。
堆:紧随着代码和数据的是堆,代码和数据区在进程一开始运行时就被规定了大小。当调用入malloc和free这样的C标准库函数时,对可以在运行时动态地扩展和收缩。、
共享库:地址空间的中间部分是用来存放像C标准库和数学库这样共享库的代码和数据的区域。共享库的概念非常强大,也相当难懂。
栈:用户栈,用它来实现函数调用。
内核虚拟存储器:内核总是驻留在内存中,是操作系统的一部分。对用户代码来说是不可见的。
虚拟存储器的运作需要硬件和操作系统之间非常复杂的配合,包括对处理器生成的每个地址的硬件翻译。其基本思想就是把一个进程虚拟存储器的内容存储在磁盘上,然后用主存作为磁盘的高速缓存。
图:进程的虚拟地址空间
文件
文件就是字节序列,仅此而已。每个I/O设备,包括磁盘,键盘,显示器,甚至网络,都可以视为文件。系统中的所有输入输出都是通过使用一小组称为Unix I/O 的系统函数调用读写文件来实现的。
文件这个概念简单精致但内涵丰富。它向应用程序提供了统一的视角,来看待系统中可能含有的各式各样的I/O设备。
====================================================
系统之间利用网络通信
现代系统通常通过网络与其他系统相连。从单一的系统视角来看,网络可视为一个I/O设备。网络-网络适配器的模型,说明网络也是一种I/O设备。
客户端和服务器的交互模式在网络应用中是非常常见的 。
====================================================
重要主题
系统不仅仅是硬件,系统是硬件和系统软件互相交织的集合体。
并发和并行
两个需求:计算机做得更多,计算机做得更快;
推动了驱动的进步。
并发是一个通用的概念,是指一个同时具有多个活动的系统;
并行指的是用并发使一个系统运行得更快;
并行可以在计算机系统的多个抽象层次上运用。
1线程级并发
对于单核系统来说,这种并发只是模拟出来的。
多核才能实现真正的并发;
2指令级并行
现代处理器可以同时执行多条指令的属性被称为指令级并行。
3 单指令、多数据并行
计算机系统中抽象的重要性
抽象的使用是计算机科学中最为重要的概念之一;
指令集结构:提供了对处理器硬件的抽象;
这里再增加一个抽象:虚拟机,它提供对整个计算机的抽象。
====================================================
小结
计算机系统是由硬件以及软件组成的,它们共同协作以运行应用程序。计算机内部的信息被表示为一组组的位。它们根据上下文有不同的解释方式。程序被其他程序翻译成不同的形式,一开始是ASCII文本,后来被编译器和链接器翻译成二进制可执行文件。
存储设备划分层次结构;
操作系统内核是应用程序与硬件之间的媒介,它提供三种基本的抽象:1)文件是对I/O设备的抽象。2)虚拟存储器是对主存和磁盘的抽象。3)进程是对处理器、主存和I/O设备的抽象。
网络提供计算机系统之间通信的手段,从特定操作系统的角度看,网络就是一种I/O设备抽象。