本文转载自微信公众号《神光的编程秘籍》,作者神说,必有光zxg。转载本文请联系神光编程秘籍公众号。一些关于计算机原理的思考,随便看看。硬连线到冯·诺依曼其实最早的计算机是没有存储机制的,是通过硬连线来编程的。编程就是接线。后来的电子计算机有了存储机制,可以存储一些指令和数据,这样就有了可重用程序存在的基础,就是通过电和磁来存储二进制信息,代替了硬接线。计算机之所以能存储,是因为它是图灵机模型的实现。存储部分对应图灵机模型中的纸带。冯·诺依曼架构(现代计算机的架构)是图灵机的实现。它设计用二进制来表示机器码、存储和计算机的五个主要组成部分:输入、输出、控制、计算和存储。现在的计算机有cpu中的寄存器、L1、L2、L3缓存,还有内存和硬盘的存储方式。这6级存储介质就是计算机的存储系统。随着计算机发展到现在的存储系统,存储已经是常识。存储是程序复用的基础,一些写得好的代码是可以重复执行的。而且,编译的出现和发展,让我们不用输入机器码,就可以用字符组成的高级语言进行编程,然后编译成二进制机器语言。cpu、时钟和跳转程序最终由cpu执行,cpu执行的指令由CS+IP寄存器控制。cpu会不断的取这两个寄存器所代表的内存地址的指令,通过数据总线读入cpu。经过译码器译码后,由不同的电路执行。取指令、译码、执行指令是CPU一个恒定的循环,CPU会无限循环这个过程。指令周期的执行频率受时钟控制,具有一定的频率。有些电脑可以支持短期超频,就是提高这个时钟的频率。cpu不断循环着时钟周期,所以总要有一个起始地址,一般是固定地址,计算机开机后加载的第一条指令。这部分代码称为BIOS(BasicInputandOutputSystem),是后续所有程序执行的基础。指令支持跳转到另一个地址,并以这种方式支持控制流。如上所述,cpu不断循环时钟周期,因此必须有一种方法来控制它的转向。控制转向的功能是通过跳转指令实现的,所以跳转指令就是cpu的方向盘。指令和数据可以放在内存的任何位置,cpu可以通过跳跃方向盘控制在那里运行。cpu是汽车,那么时钟就是发动机,控制着cpu执行指令的频率,CS+IP寄存器中存放的是哪条指令,它只会向前行驶,也就是只会不断取指一条指令,而转向(即控制流)是由跳转指令控制的,它运行在内存中的任意位置取指令并在cpu上运行,而第一段路就是BIOS程序所在的地方.BIOS、裸机和操作系统BIOS程序一般不是自己写的,除非是直接在裸机(没有操作系统的电脑)上嵌入开发的,那么就需要自己对程序进行引导,可以控制指令在哪里存储和数据存在于何处,从何处获取。这种逻辑太笼统了,而且只有一个控制流,只有一个路由和风景,不能充分利用cpu。为了解决这个问题,出现了一个操作系统,可以有多个控制流,也就是汽车有多个行程,可以看到沿途不同的风景。操作系统也有自己的BIOS程序,这是CPU的开始。它将CPU带到操作系统所在的地方。操作系统一般会提供进程机制,并对内存进行管理。它不再是随意使用。相反,它需要应用,就像我们企业管理的东西将被用作审批流程。申请之后会分配内存,进程的程序会放在这块内存中。逻辑是一个控制流,一个进程可以有多个控制流。虽然一台车(一个cpu)同时只能在一个地方运行,但是当其他代码不需要它的时候,它可以为其他进程运行。这就像在你不需要的时候和别人一起兜风。cpu不是一直在运行吗?为什么不使用它?因为磁盘或者网卡等设备都有自己的控制器,叫做DMA。跑到那个地方,就会让DMA搬运东西,就像打电话自己提货搬东西一样。当DMA将设备数据传输到内存中时,CPU需要等待,处于空闲状态。这个时候最好运行其他代码,当然你也可以什么都不做就在那里等着(阻塞等待)。cpu可以在io期间运行其他代码。运行的路由称为控制流。控制流有两种,一种是进程,一种是线程。线程可以访问进程分配的内存等资源,不同的进程各自分配的资源不能互相访问,需要使用其他内存进行调用。我们知道,程序可以访问和操作裸机上的所有内存,这是由程序自己控制的,但是有了操作系统,就必须遵循操作系统的规范。操作系统对可执行文件有格式要求,只有某种格式才能作为Machinecode来执行,windows上的exe格式,linux等系统上的elf格式。elf格式会把文件分成代码段(text)和数据段(data)等不同的部分来存放不同的数据,这样文件就会被加载到内存中,放在不同的地方,然后执行代码从text段中,从data段中取出全局数据,以及运行时调用栈和堆占用的内存。不同的进程在自己的内存中加载自己的可执行文件,然后在执行过程中形成不同的控制流,在栈和堆上放入不同的数据。这是操作系统限制的内存管理。它是由操作系统决定的。与裸机相比,它的自由度较低(必须做成可执行文件格式),但它拥有更多各种操作系统提供的能力(系统调用和标准库)。操作系统和vm的内存管理操作系统给运行可执行文件的进程分配内存,然后这个进程内部可以进行划分,比如vm,会对自己的内存再次进行内存管理,各种解释languages就运行在这块内存上,因为是你自己管理的,不需要不同的操作系统有不同的内存格式,可以统一为一个(跨平台)。比如jvm有方法区、静态域、堆、栈等,而jsvm有全局作用域(类似静态域)、调用栈(函数上下文的栈)、堆等。因为这些VM实现了一个内存管理层本身,其上运行的字节码的内存管理方法不是操作系统,而是由VM自己设计的。但是不管怎么设计,还是需要存储代码和数据。动态分配基本在堆上,全局数据放在静态域,有调用栈维护上下文。这基本上是一个通用的设计。内存管理主要是管理代码和数据在内存中某个位置的写入和修改,通过变量引用某块内存,不同的变量类型引用不同大小的内存。从裸机上内存的随意修改,到操作系统上进程的有限运行内存,再到vm上内存的进一步设计。不同层级会做出自己的设计,但总是交给CPU来运行。当CPU运行到这块内存时,使用跳转控制转向,利用操作系统提供的线程能力运行不同的路线(控制流程)。综上所述,本文主要梳理一些计算机的历史和原理。从硬布线到冯诺依曼系统再到6级存储系统的发展过程是发展历史的一部分,CPU的指令周期和时钟频率是CPU的工作。这样CPU就不断地执行指令周期,通过跳转指令跳转到其他地方(改变控制流程)。上层高级语言封装了if、else、基于跳转的函数调用。计算机执行的第一个引导程序是BIOS,裸机和操作系统都需要它。操作系统提供管理进程的能力,可能同时有多个控制流,提供各种软硬件管理能力,暴露系统调用和标准库。操作系统可以加载某种格式的可执行文件。不同的系统对进程有自己的内存管理方式,而vm是对操作系统分配的内存进行自己的内存管理。现在很多跨平台的软件都是基于这种在vm上运行的语言。虽然不同VM的内存管理设计不同,但是栈等设计确实是通用的。注意:虽然我们在做前端开发的时候不需要太了解计算机原理,但是了解计算机就是提升内功,内功提升了,任何开发都会有更深刻的理解。本文只是随手写的一些想法,希望抛砖引玉,引起大家对计算机原理的思考。
