前言
这是我第二次读《深入理解计算机系统》,这次的目标是更深入一些,把自己的理解表达出来,同时也是再巩固下基础,越是底层的知识越是经得起时间的考验。
系统硬件的组成
一个计算机系统是由硬件和软件组成的,了解硬件有助于我们写出更好的程序代码。该图是一个典型系统硬件的组成
总线
总线贯穿整个系统,将信息字节传递给各个部件。但是一般这个“字”被设置为指定长度,字长是一个系统级别的参数,每个系统的字长不一样,32位系统字长是4个字节,64位系统是8个字节。
I/O设备
输入/输出设备是系统和外界沟通的桥梁,图中的鼠标、键盘、显示器还有磁盘都是I/O设备。每个I/O设备需要通过一个控制器或者适配器和系统相连。例如图中的USB控制器、图形适配器等。
主存
从物理上讲,主存是由一组DRAM(动态随机存取存储器)组成;从逻辑来讲,主存是一个线性的字节数组,每个字节都有一个唯一的地址(索引)。
组成程序的指令字节大小是不同的,就运行在64位的C程序来说,short需要2个字节,int和float需要4个字节,而long和double需要8个字节。
CPU
中央处理器,简称处理器,是用来解释或执行主存中的指令。处理器的核心是一个大小为一个字的存储设备(例如这个设备是寄存器),我们称为程序计数器(PC)。任何时刻PC总是指向主存中机器语言的某个指令。
从通电的一刻起,处理器就一直不断地执行程序计数器执行的指令,围绕着主存,寄存器文件和算数/逻辑单元(ALU)进行
什么是信息?
在计算机系统中,信息都是通过一串bit来表示的,也就是0和1。要区分不同的数据表达什么信息,唯一的方法就是知道该bit的上下文,在不同的上下文同样是一个字节序列可能表达的意思不尽相同。就好像中文的“意思”,不同的语境含义是不同的,上下文就相当于语境。因此计算机系统中,信息=bit+上下文。
程序是如何运行的?
了解了上面几个硬件的作用,我们来运行下一个简单的hello程序。
编写hello.c代码:
#include <stdio.h>
int main()
{
printf("hello,world\n");
return 0;
}
用gcc进行编译,得到一个可执行目标文件hello,
> gcc -o hello hello.c
运行hello程序
> ./hello
> hello,world
当输入./hello
为何需要高速缓存?
上述例子非常简单,但是有一个很重要的问题,我们执行hello程序,把它从磁盘复制到主存,又复制到了处理器,这些复制对系统来说就是开销,因此我们要减少复制操作。根据机械原理,较大的存储设备要比较小的存储设备运行慢,为了解决这个差异,系统设计者采用高速缓存存储器来来处理这一问题,从上到下,访问速度越来越慢,但容量越来越大,上一层的存储器是下一层存储器的高速缓存。下图是各个存储设备层次结构图:
实现高速缓存的一个重要原因是利用了局部性原理,程序具有访问局部区域数据和代码的趋势,可以让大部分原来在内存的操作可以在高速缓存中完成,从而将程序的性能提高一个数量级。
操作系统是如何管理硬件的?
这小节是本篇的核心,理解抽象这个伟大的设计技巧,尤其是对面向对象语言的程序员来说,抽象是个很厉害的能力。正如一句话所说那样:Any problem in computer science can be solved by anther layer of indirection.
上面我们介绍了如何运行一个hello
程序,操作者要执行一个程序,需要一系列的硬件设备配合来完成,例如上面说到的键盘、主存、磁盘、显示器,仔细看会发现它们并不是直接操作程序的,而是需要通过系统来间接完成各自所要实现的功能,操作系统好比一个指挥官对各个部件进行安排,分配资源,以保证它们能各尽其职。
为了更好的管理硬件设备,操作系统通过这几个基本抽象概念来实现:
- 进程
- 虚拟内存
- 文件
所谓的抽象概念是想象出来的并不是真实存在的,有人说文件不是真实存在吗?一张图片,一部电影都是文件,实实在在的存在我的磁盘上。但此文件并非彼文件,这里的文件是指的是对I/O设备的抽象。
进程
进程是操作系统对一个正在运行程序的抽象,一个系统可以同时运行多个进程。任何一个时刻一个CPU只能处理一个进程的代码,一个CPU看上去是在并发地执行多个进程,实际上是靠不断的切换进程来实现的,操作系统实现这种切换的机制叫做上下文切换,操作系统还需要保持跟踪进程运行所需要的状态信息,这个状态信息也称为上下文。
从一个进程到另一个进程的转换是由操作系统内核(kernel)管理的,内核不是一个进程,它是系统管理全部进程所用代码和数据结构的集合。
线程
一个进程实际由多个线程组成,每个线程运行在进程的上下文中。相对于进程来说,线程之间更容易共享数据且高效。
虚拟内存
虚拟内存为每一个进程提供了一个假象,让每个进程以为自己独占地使用主存,每一个进程看到的内存都是一致的,称为虚拟地址空间,虚拟地址空间由这几个部分组成:
- 内核虚拟内存,该区域是为内核保留的
- 堆
- 共享库
- 栈,编译器用它来实现函数调用
- 程序代码和数据
文件
文件就是字节序列。只要是I/O设备,例如磁盘、键盘、网络等都可以看做是文件,文件为应用程序提供了一个统一的视图
小结
计算机系统是由硬件和系统软件组成的,它们共同协作来运行应用程序。计算机内部信息被表示为一组组的位,通过上下文它们有不同的解释。
计算机花费了大量的时间在内存、I/O设备和CPU寄存器之间复制数据,因此划分出了储存设备层次结构,用高速缓存来减少各个存储设备之间的复制,从而提高程序性能。
操作系统内核是应用程序和硬件之间的媒介,操作系统通过抽象来管理和控制硬件设备。文件是对I/O设备的抽象;虚拟内存是对主存和磁盘的抽象;进程是对一个正在运行程序的抽象。而网络也是一种I/O设备。
本篇介绍了计算机系统的组成,对于使用高级语言进行软件开发的同学来说,各种框架、开发语言不断迭代新出,但系统内在的这些概念却没有太多变化。这些知识的复利非常的高,能帮助我们在技术的路上越走越远。
参考资料
- 阮一峰:编译器的工作过程
- 《深入理解计算机系统》网盘资源:mq1e
请你相信我所说的都是错的