计算机的分类
- 终端设备(台式机,笔记本,手机,Pad…) 平时用户使用的
- 服务器 普通用户见不到,开发人员经常打交道
- 嵌入式设备 主体功能不是用来计算,而是针对一些特定的场景,量身定做的"专用计算机"
冯诺依曼体系(Von Neumann Architecture)
现代的计算机, 大多遵守 冯诺依曼体系结构
- CPU 中央处理器: 进⾏算术运算和逻辑判断.
- 存储器: 分为外存和内存, ⽤于存储数据(使用⼆进制方式存储)
- 输⼊设备: 用户给计算机发号施令的设备.
- 输出设备: 计算机给用户汇报结果的设备.
- 寄存器 ≠ 存储器。寄存器 是CPU上的一个模块;存储器 是内存 + 硬盘的统称
有的硬件设备,可能既是输入,也是输出: 蓝牙,网卡,触摸屏
除了硬盘,其他存储空间断电数据就会丢失
存储空间 | 访问速度 | 易失性 | 成本 | 访问权限 | |
---|---|---|---|---|---|
内存 | 较小 | 较快 | 系统断电时,数据就会丢失 | 较高 | CPU能直接访问内存 |
外存 | 较大 | 较慢 | 即使没有电源,也能保存数据 | 较低 | 外存的东西要先到内存,CPU才能处理 |
现代的 CPU往往还提供"缓存模块"
在我这个CPU上,有三个缓存。数字越小,速度就越快,存储空间也越小
有些数据,可能要被 CPU频繁使用,每次使用都从内存读取,就比较慢。就可以把这样的高频使用数据放到缓存中(数据使用频率特别高,放到L1 缓存;数据使用频率没那么高,考虑放到L2 / L3)
CPU取数据的时候,先看看缓存里有没有,没有就读取内存,有的话直接读缓存。
数据从内存/缓存来 -> CPU加工 -> 写回内存/缓存
CPU
主要功能:
- 进行各种算术运算
- 进行各种逻辑判断
任务管理器中可以查看CPU占用率和频率
频率描述了CPU干活的效率,数字越大,干活越快。
指令(Instruction)
程序猿写的程序都会被编译成计算机能识别的二进制指令(机器语言), CPU被设计出来的时候,CPU厂商就会约定,这个CPU上都能支持哪些指令。程序猿通过这些指令来指挥CPU干活。Java的字节码只是JVM能识别,JVM还会把字节码翻译成CPU认识的指令。而二进制指令和汇编语言是一 一对应的
指令 就可以认为是 CPU给程序猿提供的一些"编程接口", 不同的 CPU提供的指令是不一样的。虽然不相同,也是有几套标准的
- 最主流的一套标准是 x86 架构的CPU
Intel & amd 生产的 PC/服务器 都属于 x86系列的 CPU
- 另一套也非常流行的标准是 arm 架构
手机,平板,各种嵌入式设备…
性能不及 x86, 但是功耗比较低(省电),比较适合移动设备
指令主要由操作码 + 被操作数组成。
其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也可能是寄存器编号等。
指令本身也是⼀个数字,用⼆进制形式保存在内存的某个区域中。
CPU如何执行指令的
所谓的指令,都是要先加载到内存中,然后才能被CPU读取并执行
比如: 一个Java程序,写出来是一个.Java源代码文件,编译得到.class二进制文件(仍然是在硬盘上),运行程序的时候,JVM就会把这个.class加载到内存中,再进一步翻译成CPU能识别的二进制指令
再比如:一个 C程序,写出来是一个.c源代码文件,编译得到 .exe二进制文件(也是在硬盘上),运行的时候,操作系统会把这个.exe文件加载到内存中,再进一步由CPU执行
CPU上也能存数据,存储数据的模块就称为"寄存器",速度比内存更快,但存储空间更小,往往就是几百个字节左右
内存,存储空间比硬盘小,速度比硬盘快3~4个数量级,相同的存储大小价格比硬盘贵,掉电后数据丢失
寄存器,存储空间比内存还小,速度比内存还快3~4个数量级,相同的存储大小价格比内存更贵,掉电后数据也丢失
冯诺依曼体系结构规定:
一个程序,指令和依赖的数据,都是要在存储器中保存的。CPU如果需要执行,都是要自动地从存储器中读取到对应的指令的
CPU执行程序,大概就是经历三个阶段:
1.读指令(把内存中的指令数据,读到 CPU的寄存器中)
2.解析指令(理解当前指令要做啥)
3.执行指令
这只是"简化版"模型,实际的CPU会更复杂,下面我也用"简化版"指令表进行演示
指令名称 | 功能说明 | 4位 opcode(操作码) | 操作的地址或者寄存器(被操作数) |
---|---|---|---|
LOAD_A | 从 RAM 的指定地址,将数据加载到 A寄存器 | 0010 | 4位RAM 地址 |
LOAD_B | 从 RAM 的指定地址,将数据加载到 B寄存器 | 0001 | 4位RAM 地址 |
STORE_A | 将数据从 A寄存器写入 RAM 的指定地址 | 0100 | 4位RAM地址 |
ADD | 计算两个指定寄存器的数据的和,并将结果放入第二个寄存器 | 1000 | 2位的 寄存器ID 2位的 寄存器ID |
每个CPU被设计出来都会提供一个这样的指令表
- RAM是内存(随机存取存储器)
- CPU的寄存器数量都是固定的,一般都是使用字母/数字的组合来命名,我这里的例子中就只有A寄存器和B寄存器
- 4位 opcode (操作码) 区分是一个啥样的操作
- 操作的地址或者寄存器相当于被操作数,即针对什么进行操作(类似于函数的参数)
- 假定A寄存器的ID是00, B寄存器的ID是01
我的例子中的指令是8位的二进制数字,前4位用来区分这是一个啥样的指令(操作码),后四位是被操作数。实际上现代的CPU一条指令都是更长的,不仅仅是8位(不过大体也是通过 操作码 + 被操作数构成的)
地址 | 数据 |
---|---|
0 | 00101110 |
1 | 00011111 |
2 | 10000100 |
3 | 01001101 |
4 | 00000000 |
5 | 00000000 |
6 | 00000000 |
7 | 00000000 |
8 | 00000000 |
9 | 00000000 |
10 | 00000000 |
11 | 00000000 |
12 | 00000000 |
13 | 00000000 |
14 | 00000011 |
15 | 00001110 |
这段内存的数据就描述了一段程序,需要结合指令表来进行理解。数据中前4个是指令,后两个是数据,都是系统安排好的
所谓程序,就是⼀组指令以及这组指令要处理的数据。狭义上来说,程序对于我们通常表现为⼀组⽂件。
程序 = 指令 + 指令要处理的数据。
地址是 内存里的概念, CPU操作内存的时候,要根据地址,来获取/修改 里面的数据
数组之所以能以O(1)复杂度取下标元素,本质上就是内存提供了随机访问能力
CPU中有一个专门的寄存器,保存接下来要从哪个内存地址中取指令,不同CPU对其叫法都不一样,有些书上称为"程序计数器",简称"pc"
此处假设从0号地址开始执行,CPU每次读取执行完一个指令之后,就会自动把pc中的值进行+1,顺序读取下一条(如果遇到一些 跳转类指令,就不是+1,而是被设置成特定的地址)
第一轮操作:
1)CPU取出0号地址的指令 :00101110
2)解析指令,去指令表中查询
操作码:0010
, 所以是LOAD_A指令,也就是将地址为被操作数上的数据加载到A寄存器
被操作数:1110
, 因为是LOAD_A指令,表示地址,二进制的1110,就是十进制的14
3)执行指令
把14地址这里的数据取出来,也就是00000011
,十进制是3,放到A寄存器中
第二轮操作(由于刚才不是跳转指令,pc中要取的地址顺延(顺序+1)):
1)CPU取出1号地址的指令 :00011111
2)解析指令,去指令表中查询
操作码:0001
, 所以是LOAD_B指令,也就是将地址为被操作数上的数据加载到B寄存器
被操作数:1111
, 因为是LOAD_B指令,表示地址,二进制的1111,就是十进制的15
3)执行指令
把15地址这里的数据取出来,也就是00001110
,十进制是14,放到B寄存器中
第三轮操作:
1)CPU取出2号地址的指令 :10000100
2)解析指令,去指令表中查询
操作码:1000
, 所以是ADD指令,也就是计算两个指定寄存器的数据的和,并将结果放入第二个寄存器
被操作数:0100
, 因为是ADD指令,此时就不是内存地址了,而是表示l两个寄存器的ID,一个是01(B寄存器),一个是00(A寄存器)
3)执行指令
将这两寄存器中的数值进行相加,指令表中约定了ADD操作要把相加的和放到第二个寄存器中,也就是00(A寄存器)
第四轮操作:
1)CPU取出3号地址的指令 :01001101
2)解析指令,去指令表中查询
操作码:0100
, 所以是STORE_A指令,也就是将将数据从 A寄存器写入 地址为被操作数的内存中
被操作数:1101
, 因为是STORE_A指令,表示地址,二进制的1101,就是十进制的13
3)执行指令
把A中的数据17写入到内存地址为13这个单元中
地址 | 数据 |
---|---|
0 | 00101110 |
1 | 00011111 |
2 | 10000100 |
3 | 01001101 |
4 | 00000000 |
5 | 00000000 |
6 | 00000000 |
7 | 00000000 |
8 | 00000000 |
9 | 00000000 |
10 | 00000000 |
11 | 00000000 |
12 | 00000000 |
13 | 00010001 |
14 | 00000011 |
15 | 00001110 |
第五轮操作:
1)CPU取出4号地址的指令 :00000000
2)解析指令,去指令表中查询
指令表中没有一般就表示程序运行完毕
3)执行指令
程序退出
操作系统(Operating System)
软件就是一组指令的集合
操作系统是⼀组做计算机资源管理的软件的统称。⽬前常见的操作系统有:Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。
操作系统就是为了把一个计算机上所有硬件资源和软件资源都管理好
- 管理好各种硬件资源,让他们能很好的相互配合
- 管理好各种软件资源,给每个软件都提供稳定的运行环境
操作系统 = 内核(负责管理) + 配套的应用程序(靠内核提供的一些功能作为支撑)
C语言的
#include <stdio.h>
int main()
{
printf("Hello, World! \n");
return 0;
}
这样一段代码就是一个"应用程序",需要操作显示器。显示器是硬件设备,不是程序直接操作的,是程序告诉操作系统"我要操作显示器",操作系统完成这个功能的
操作系统内核就会给应用程序提供一系列API,有的API操作显示器,有的 API 响应鼠标键盘, 有的 API操作网卡
操作系统通过驱动程序操作硬件
同一种硬件,不同厂商产出来的具体细节都会有区别。硬件生产商就需要通过驱动程序告知我们硬件具体的特点和使用详情