计算机系统
2022/9/7 18:42 因为直接纯看《CSAPP》过于枯燥,所以这里建议结合视频【CSAPP-深入理解计算机系统】1-1.计算机系统漫游_哔哩哔哩_bilibili一起食用;
前言(一)
首先简单介绍一下《深入理解计算机系统》这本书与其他计算机教材的不同之处
常规课程体系中缺乏一门独立的能够贯穿整个计算机系统的基础课程;
该教材系统地介绍了整个计算机系统的工作原理,可帮助学生系统性地理解计算机如何执行程序、存储信息和通信;
该教材从程序员的角度看待计算机系统,重点讨论系统的不同结构对于上层应用软件编写、执行和数据存储的影响,以培养程序员在更广阔空间应用计算机系统知识的能力;
这本书有些地方讲的挺好,有些地方(如第二章的数据的表示讲的太复杂了)没必要花费大量时间去研究,本博客中只记录较为重要的一些知识点;
计算机系统漫游(二)
本章就是按照从计算机系统底层到顶层,从硬件到软件再到通信,从计算机组成原理到计算机操作系统到计算机网络的顺序介绍了整个计算机系统中重要的概念;
1.计算机系统的组成
计算机系统是由硬件和软件组成的,它们共同工作来运作应用程序;
2.计算机系统的信息
一个基本思想:计算机系统中所有的信息—包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的;
区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文 —— 即计算机内部的信息被表示为一组组的位,它们依据上下文有不同的解释方式;
3.编译系统
这里简单再介绍一下编译系统(详细介绍可以参考《程序员的自我修养》)
通常我们直接使用IDE类似黑盒的方式对程序进行编译并执行,但了解编译系统如何工作可以使我们知道发生编译错误时问题出在哪里以及如何优化程序性能(编译器自动优化的性能可能比不上手动优化)等
4.操作系统
关于操作系统,因为一开始跟着王道视频学习所以可能理解并不深刻,需要在后续学习过程中反复巩固;
操作系统是应用程序和硬件之间插入的一层软件,所有应用程序对硬件的操作尝试都必须通过操作系统;
操作系统有两个基本功能:
- 防止硬件被失控的应用程序滥用;
- 向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备;
操作系统通过几个基本的抽象概念(进程、虚拟内存和文件)来实现这两个功能;
文件是对I/O设备的抽象表示;
虚拟内存是对主存和磁盘I/O设备的抽象表示;
进程是对处理器、主存和I/O设备的抽象表示;
实际上还有第四个抽象,即虚拟机
是对整个计算机的抽象,包括操作系统、处理器和程序;
4.1 进程
当某个程序运行在现代计算机系统上时,程序看上去是独占地使用处理器、主存和 I/O 设备,即处理器看上去就像在不间断地一条接一条地执行该程序中的指令,该程序的代码和数据是系统内存中唯一的对象;
上述的假象通通是进程的概念实现的;
进程
是操作系统对一个正在运行的程序的一种抽象,在一个系统上可以同时运行多个进程,而每个进程都好像在独占地使用硬件;
并发运行
是说一个进程的指令和另一个进程的指令是交错执行的;操作系统保持跟踪进程运行所需的所有状态信息,这种状态就是
上下文
;
上下文切换
指的是当操作系统决定要把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文、恢复新进程的上下文,然后将控制权传递到新进程;从一个进程到另一个进程的转换是由操作系统
内核(kernel )
管理的。 内核是操作系统代码常驻主存的部分,内核不是一个独立的进程。相反,它是系统管理全部进程所用代码和数据结构的集合;
4.2 线程
在现代系统中,一个进程可以由多个称为线程
的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据;
多线程之间比多进程之间更容易共享数据,也因为线程一般来说都比进程更高效,因此网络编程中我们常用多线程实现并发;
4.3 虚拟内存
虚拟内存为每个进程提供了一个假象,即每个进程都在独占地使用主存;
且每个进程看到的内存都是一致的,称为虚拟地址空间,下面我们展示Linux中的进程的虚拟地址空间
每个进程看到的虚拟地址空间
由大量准确定义的区构成,每个区都有专门的功能,这里以Linux进程的虚拟地址空间从低地址开始简单介绍虚拟地址的区;
- 代码和数据区:代码和数据区是直接按照可执行目标文件的内容初始化的,在示例中就是可执行文件;
- 堆区:代码和数据区后紧随着的是运行时堆,代码和数据区在进程一开始运行时就被指定了大小,与之不同堆可以在运行时动态地扩展和收缩(如执行malloc和free函数时);
- 共享库:在虚拟地址空间的中间部分是一块用来存放像 C 标准库和数学库这样的
共享库的代码和数据
的区域; - 栈区:位于用户虚拟地址空间顶部的是用户栈,编译器用它来
实现函数调用
。栈区在程序执行期间也可以动态拓展和收缩,例如,每次我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩; - 内核虚拟内存:此段属于用于代码不可见的内存部分,位于虚拟地址空间的最上面。不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数;
4.4 文件
文件就是字节序列,仅此而已。每个 I/O 设备,包括磁盘、键盘、显示器,甚至网络,都可以看成是文件(Linux中一切皆文件);
文件向应用程序提供了一个统一的视图,来看待系统中可能含有的各式各样的 I/O 设备 —— 简单来说就是编写的一个具备I/O功能的程序可以在使用不同的磁盘技术上的不同操作系统上运行;
5.重要概念
5.1 Amdahl定律
当我们对系统的某个部分
加速时,其对系统整体
性能的影响取决于该部分的重要性和加速程度
;
5.2 并发和并行
首先是这两个概念很容易让人混淆,在网上找了一圈找到一个通俗易懂的比喻,我们用下面这幅图解释
图中,我们令咖啡机为CPU,队列为待处理的任务,排队小人作为任务的每个步骤
- 无论是并发还是并行,前提一定是有多个任务要处理,也就是图中咖啡机前的队列数量一定大于等于2;
- 并发还需要具备一个前提是,要处理的任务一定是可分步骤的,也就是队列中的人的数量一定大于等于2;
- 并行还需要具备一个前提是,必须要有多个处理器,也就是咖啡机的数量一定要大于等于2;
- 假如环境中只有一个单核处理器,则实现不了并行;假如任务可分步骤则可实现并发,否则并行和并发均无法实现;
- 假如环境中有一个多核处理器或多个单核处理器,则可以实现并行;假如任务可分步骤则可实现并发,否则只能实现并行无法实现并发;
程序结构和执行(三)
1.数据的表示和处理
计算机将信息编码为位(比特),通常组织成字节序列;
- 现代计算机存储和处理的信息以二值信号(二进制数字)表示;
- 大多数计算机使用 8 位的块,或者字节(byte) , 作为最小的可寻址的内存单位,而不是访问内存中单独的位;
2.程序的机器级表示
首先明确现代计算机的多级划分:
第一级是微程序设计级,这是一个硬件级别,由机器硬件直接执行微指令;
第二级是一般机器级,也称为机器语言级,也是硬件级,由微程序解释机器指令;
第三级别是操作系统级,由操作系统程序实现,软件级;
第四级是汇编语言级,由汇编程序支持和执行,软件级;
第五级是高级语言级,由各种高级语言编译程序支持和执行,软件级;
graph TB;
高级语言级-->汇编语言级
汇编语言级-->操作系统级
操作系统级-->机器语言级
机器语言级-->微程序设计级
我们这里讨论机器级的程序表示,然而会发现实际上讨论的都是汇编代码——这是因为计算机执行机器代码,但是C语言编译器将高级语言
转换输出的是汇编语言
(注意不是机器语言!!!经过汇编器和链接器后才是可执行的机器代码),汇编语言
是机器代码的文本表示(也是我们在计算机组成原理中形如MOV、ADD的这种指令),是人类可读的机器代码的表示(如果真的拿机器代码给我们学1100 0010根本就学不下去)
- 高级语言提供了大量抽象,屏蔽了程序在机器语言级的实现,使得效率很高同时可以在不同机器上编译和执行;However,高级语言的这种抽象也可能会隐藏我们需要知道的一些细节,这就必须得往底层语言学习;
- 汇编语言和机器语言依赖于特定机器,但是学习汇编语言(默认不学机器语言,不是咱们一般人学的)可以理解编译器的工作机制、优化能力以及手动优化汇编代码提高程序执行效率;
其他的高级语言和汇编语言之间的区别(如寄存器的可见性、指令执行顺序的抽象、汇编语言不区分数据类型等)我们就不再赘述,感兴趣可以自行查阅;
2.1 过程
过程是程序中的一种抽象,提供了一种封装代码的方式(可以类比对象,实际上面向过程编程就是面向函数编程),用一组指定的参数和一个可选的返回值实现了某种功能(函数的定义);
不同的编程语言中过程的叫法不同:函数、方法、子例程、处理函数等;
要提供对过程的机器级支持,需要如下机制(假设过程P调用过程Q,Q执行完毕后返回P):
传递控制:在进入过程Q的时候,程序计数器必须被设置为Q的代码的起始地址,然后在返回时,要把程序计数器设置为P中调用Q后面那条指令的地址;
传递数据:P 必须能够向Q提供一个或多个参数,Q必须能够向P返回一个值;
分配和释放内存:在开始时,Q可能需要为局部变量分配空间,而在返回前,又必须释放这些存储空间;
(1)运行时栈
为了解决传递控制的问题,C语言使用了后进先出的栈结构,这样当后进来的Q执行完毕后与其相关的局部变量空间都会被释放(Q执行过程中P一直挂在栈中),
运行时栈的通用结构如下,主要分为栈帧、寄存器(栈顶指针也属于一个寄存器)等存储空间
(2)数据传送
当调用一个过程时,除了要把控制传递给它,并且在过程返回时再传递回来之外,过程调用还可能把数据作为参数传递,而从过程返回还有可能包括返回一个值;
大部分过程间的数据传送是通过寄存器实现的——注意寄存器组是唯一被所有过程共享的资源;
当出现下列情况的时候局部数据不能只存放在寄存器中,必须存放在内存中(也就是不存在寄存器中而是存放在栈帧中)