• 【JavaEE】计算机是如何工作的


    冯诺依曼体系

    现代的大多数计算机, 都遵循冯诺依曼体系
    在这里插入图片描述

    • CPU 中央处理器: 进行算术运算和逻辑判断
    • 存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)
    • 输入设备: 用户给计算机发号施令的设备
    • 输出设备: 计算机个用户汇报结果的设备.

    CPU 内存 磁盘的比较

    • 存储空间上
      • CPU << 内存 < 磁盘
    • 读取速率上
      • CPU >> 内存 > 磁盘

    寄存器 和 内存

    • 寄存器是CPU的一部分;
    • 寄存器, 和内存与磁盘相比, 存储空间更小, 访问速度更快, 成本更高, 掉电后数据丢失。
    • 寄存器的速度和内存的速度的差距是极大的,3~4个级别
    • 寄存器的用途,就是辅助 CPU 完成指令的执行;一条指令,不仅仅是指,指令本身,同时还有操作数,操作数就是要在寄存器中保存的

    由于 寄存器 和内存之间速度和空间上差异太大了,难以协调工作,CPU往往又引入了“缓存”来调和 寄存器 和 内存之间的速度。

    CPU 上要进行一系列运算,在运算过程中,要反复使用到一组内存中的数据,这些数据频繁使用,需要频繁访问内存,同时这些数据又比较多,在寄存器里又存不下,就可以放到缓存中了。

    缓存的存储空阿金介于 寄存器 和 内存 之间

    由于寄存器和内存之间,差距太大了,搞了一个缓存,还不太够用,后来又搞了一个。

    在这里插入图片描述

    操作系统

    操作系统的概念与定位

    • 操作系统是一个软件, 是一个搞管理的软件

      1. 对下,要管理好各种硬件设备
      2. 对上, 要给各种软件提供好一个稳定的运行环境
      • 例如: CPU, 内存, 硬盘, 各种IO设备 … 他们都是需要相互配合才能进行良好的工作的, 操作系统这个软件, 就是总指挥!
    • 计算机如何给我们解决实际问题的?

      • 依靠一些软件, 软件能够在操作系统上运行
        • 硬件千差万别,如果每个写软件的人, 都需要考虑硬件的差别和兼容性, 这个事情门槛就非常搞了, 操作系统, 就把硬件屏蔽起来, 对软件这个里提供出一组API(系统调用), 让软件来进行调用
      • 因此, 操作系统 和 JDBC 这个层面上干的是类似的工作

    进程和任务

    • 运行起来的程序叫做进程
      • 程序就是一个可以执行的文件, 只是磁盘上的一个东西
      • 如果双击程序, 此时操作系统, 就会把可执行文件中的数据和指令, 加载到内存中, 并且让 CPU 去执行这里的指令, 完成一系列的相关的工作. 运行起来的(动态的程序) 就是进程了
    • 进程能够干活, 说明进程能够消耗一定的硬件资源.
      • 可执行程序, 只是占用了硬盘空间; 而进程, 会消耗 CPU资源, 内存资源, 硬盘, 网络带宽…
    • 进程是系统分配硬盘资源的基本单位

    操作系统对进程的管理

    管理的概念

    • 为什么需要管理进程?
      • 一台正在运行的计算机, 一定会存在很多的进程正在运行;
      • 东西多了, 那很定就是需要进行管理, 才能让各个进程发挥自己的能力, 并将这些能力有效的组织起来, 高效的完成指定的工作
    • 如何进行有效的管理?
      • 管理不是"面面俱到" 不是"手把手", 这样会不仅累, 还低效
      • 高效管理的两大步骤: 先描述, 在组织
          1. 先描述: 提取要管理对象的基本信息与属性, 使用结构体或者类将其描述起来
          1. 在组织: 选用合适的数据结构, 对于新来的对象, 就通过 add 方法, 将新来的对象添加到数据结构中, 此时对于对象的管理, 就转化成对数据结构的增删改查操作了。

    操作系统对进程的管理的组织过程

    1. 描述: 会用使用一个专门的结构体, 来记录一个进程里面的各个属性
      • PCB (进程控制块) --> 通用叫法, 各种系统里面描述的进程部分都可以称为PCB
        • 在Linux中PCB, 源码中是一个 task_struct 结构体
    2. 组织: 会使用一系列的数据机构, 把多个进程进行一个有效的组织, 随时方便进行遍历, 查找, 汇总数据 …
      • 通常是使用双链表这样的方式来进行组织的 – 这个是对Linux来说的
      • 当使用双链表来组织的时候:
        • a) 查看进程的列表, 本质就是在遍历这个链表
        • b) 创建一个进程, 就是创建了一个 PCB结构体,并且插入到链表上
        • c) 销毁一个进程, 本质就是把这个PCB结构体从链表上删除并释放

    PCB 的相关信息

    1. pid 进程的标识
      • 同一个系统上, 统一时刻中, 每个进程的 pid 一定都是不同的
    2. 内存指针
      • 表示了该进程, 对于的内存资源是什么样的
      • 主要存储的就是从 exe 可执行文件中加载过来的指令(二进制的指令, 都是在程序员开发这个程序的时候, 最终编译生成的结果,也就是程序员写代码的逻辑) 和 数据
        • 指令相当于剧本, 进程就相当于表演的舞台
      • 还需要保存一些运行过程中的中间结果之类的的数据
    3. 文件描述符表
      • 和磁盘资源相关了
      • 磁盘是硬件, 应用程序一般是没法直接接触到 “硬件” 这一层的.
      • 实际上是操作系统抽象"文件"这样的概念, 程序操作的是文件, 文件实际上是存储在磁盘上的
      • 每个进程就会一个 “文件描述符表” 来记录 当前这个进程在使用哪些文件
        • 操作系统在打开一个文件, 就会产生一个 “文件描述表”(就像文件的身份表示一样, 当然只是在进程内部生效的)
        • 同时会使用文件描述符表(类似数组), 包文件描述符组织起来

    CPU 与 进程 之间的联系

    • 进程是需要在CPU上来执行指令的
      • 每个进程, 要想执行里面的指令, 完成对应的任务, 都需要在 CPU 上执行!

      • 问题提出: 一台机器上, 进程同一时刻, 有百八十个, 但CPU只有一个? 怎么办?

        • 轮着用就可以了, 进程的调度
    • CPU的发展历程
      • CPU一开始是单核的, 只能运行同时一个进程在上面运行
      • 摩尔定律: 芯片的集成程度会成倍增长, 算力会提供一倍, 成本会减半
      • 但是随着时间的增长, 摩尔定律就失效了, 因为芯片再小, 经典物理学就失效了, 量子物理学此时就生效了 – 所以芯片的继承程度不会一直增加
      • 集成程度失效了, 那就靠数量来凑 – 多核CPU
      • 又提出来超线程概念: 一个CPU可以同时跑两个进程
      • 现在的CPU就是多核多线程 – 例如六核十二线程

    CPU虽然可以让多个进程同时在一起跑来了, 但是还是不能满足所有进程, 因为CPU是有限的, 进程的数量远大与CPU的数量, 解决方法就是轮着来, 以下是解决方案:

    1. 并行: 同一时刻, 两个进程, 同时运行在两个 CPU 逻辑核心上
    2. 并发: 两个进程, 在同一个舞台上, 轮着上
    • 由于 CPU 切换进程速度极快, 微观上, 这两进程是串行执行的; 宏观上, 看起来就是这两个进程在 “同时” 执行的
    • 操作系统, 在调度这些进程的时候, 可能是按照并行的方式来调度, 也可能按照并发的方式来调度, 在应用程序这一层, 感知不到~
    • 由于感知不到是哪种方式调度, 并且这两种的调度方式, 宏观上的体现效果都是一样的, 通常也会用 “并发” 这个词来代指 “并行” 和 “并发”
    1. PCB 中关于进程调度相关的属性(这些属性也就描述了 进程 对于的 CPU 资源的使用情况) – 需要重点掌握
      1. 状态
      • 就绪状态: 一个进程已经随时做好了在CPU上执行的的准备
        • 就绪状态的意思是: 可能在CPU上跑, 也可能没有在CPU上, 而是已经做好了被CPU调度的准备
      • 阻塞状态 / 睡眠状态 : 有时候, 进程没有准备好呗调度到CPU上
      • 状态是可以相互转换的
      • 进程还有许多状态, 但是就绪和阻塞是最重要的两种状态
      1. 优先级
      • 系统给进程进行调度的时候, 也是不完全公平的, 也会根据优先级的不同, 来决定事件的分配权衡 – 这样就可以把系统资源调配给更重要的进程上了
      1. 上下文
      • 因为进程是轮着上的 – 所以一次执行, 大概率是无法完成指定的任务的, 这就需要保证下次上 CPU运行的时候, 能够找到上次运行的位置, 继续向后运行

      • 就好像存档 读档一样

      • 对于操作系统来说, 所记录的上下文是啥? 就是该进程在执行过程中, CPU寄存器中对应的数据
        • 这些寄存器, 有的是存一些中间结果, 有的是存一些特定含义的数据(比如下一条指令时在哪里, 比如当前的函数调用关系…)
        • 这些寄存器中的数据就需要在进程离开 CPU之间, 都保存好
        • 保存到对应进程的 PCB 的上下文字段中(内存中)
        • 下次该进程回到 CPU 执行, 就可以把PCB中的上下文里的数据恢复到对应的寄存器中, 这个时候就是和上次执行的状态一模一样了
      1. 记账信息
      • 相当于一个统计信息, 会统计每个进程在 CPU 上都执行了多久, 执行了多少指令.
      • 是对于进程调度工作的一个"兜底"
      • 用来调整如何分配给进程的调度时间

    进程地址空间(虚拟地址空间)

    • 进程地址空间提出的原因
      • 每个进程都需要分配到系统资源, 内存也需要分配给进程; 如果内存直接分配给进程, 此时别的进程就可能看到其他进程的相关信息,并将其修改, 导致其他的进程崩溃;

      • 并且, 直接分配内存空间, 会存在分配地址范围的不同, 且是未知的, 每个进程就需要对不同的地址进行不同的处理, 这样的代码编写会变得复杂.

      • 所以为了解决上述的问题, 在进程和内存之间提出了一个进程地址空间的概念

    • 进程地址空间的解决原理:
      • 对于非法访问地址空间的问题: 进程现在只能找进程地址空间上的地址, 操作系统在对该进程地址空间上的地址进行判断, 如果是该进程的–也就是合法的, 那操作系统在通过该虚拟地址找到所对应的物理内存的地址, 如果虚拟地址是非法的, 那么操作系统就不会允许该进程使用该地址, 并直接向该进程发送中断信号.
      • 对于地址不统一, 编写代码复杂的问题: 每个进程得到都是用同样的进程地址空间, 进程地址空间设计的时候是一样的, 所以每一个进程看到自己的进程地址空间, 结构上都是一样的, 所以代码就可以统一对该进程地址空间进行编码, 对应实际物理内存空间就交给操作系统来分配了

    进程间通信

    • 进程地址空间将进程独立开来, 每个进程只能看到自己的资源, 无法看到别人的资源, 也就无法影响别的进程, 但是, 两个进程也就无法进行信息交流了
    • 但是, 有时候, 我们需要两个进程之间进行通信 – 所以, 我们就提出了进程间通信的概念
    • 进程间通信核心: 让两个不同的进程看到同一份资源!
    • 进程间通信方案:
        1. 基于文件
        1. 基于网络
  • 相关阅读:
    【git】gitlab常用命令
    从输入URL到页面展示过程
    DownloadWithEscaping/下载数据并且转义返回数据, DownloadWithCombine/下载数据并且组合数据 的使用
    北京通信展的精华内容,都在这里!(下篇)
    Python 爬虫小练习:基于 XPath 的表格信息爬取
    使用 Veeam 进行物理到虚拟迁移
    认识ArrayList
    Node.js -- http模块
    一文看懂混沌网格(Chaos Mesh)工作原理
    Redis中的Zset类型
  • 原文地址:https://blog.csdn.net/zxj20041003/article/details/133923858