Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程

操作系统

启动过程

通电 -> bios uefi 工作 -> 自检 -> 到硬盘固定位置加载bootloader -> 读取可配置信息 -> CMOS

CMOS 用来存储可以配置的信息,需要通电才能存储信息,主板上有块电池给它通电。

鸿蒙

Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程_第1张图片
操作系统:一遍管理硬件,一般对外暴露接口,管理应用。


内核管理硬件。应用程序属于外围程序。
如未特殊说明,后面我们提到的都是Linux操作系统。

推荐一本书《Linux内核设计与实现》,是介于源码分析和应用中间的一本书,比较浅显、平实的语言勾勒出Linux内核的原理。

Kernel 内核

1、微内核 - 弹性部署 5G IoT
2、宏内核 - PC phone
3、外核 - 科研 实验中 为应用定制操作系统 (多租户 request-based GC JVM)

宏内核
相关的程序都放在一块内存里
Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程_第2张图片

微内核
万物互联:不同的占用的资源是不一样的,有的内存大,有的内存小…
鸿蒙是面向万物互联的操作系统,智能家居这样的小设备都不支持原始宏内核那样超级大的内核存在,所以使用可插拔式的微内核设计。(类似于微服务的概念)。只要有一个控制器对所有的智能家居进行控制。
部署起来特别灵活,所以叫弹性部署。

外核
针对应用定制自己的操作系统。是一个仅存在于实验室的概念,没有应用。
类似于,如果你给JVM写了一个专门针对WebServer的垃圾回收器,一个Request分配一个独立内存,Request接收之后直接将这块内存删掉(阿里正在做的多租户的GC的JVM)

VMM

由于硬件资源发展迅速,在硬件资源过剩的情况下,做出一个虚拟层(VMM:Virtual machine monitor,虚拟资源监控器),在虚拟层上面虚拟出几个操作系统,共享同一套硬件资源。

用户态、内核态

Intel CPU 分为三级:0,1,2,3三个级别
Linux 只使用了03两个级别。内核访问Ring 0级,应用程序只能访问Ring 3级。
linux内核跑在Ring 0级, 用户程序跑在Ring 3。
用户想要读硬盘、写硬盘、写网卡等,对于系统的关键访问,需要经过kernel的同意,切换到Ring 0级,保证系统健壮性。

内核执行的操作: 提供了200多个系统调用,例如 sendfile read write pthread fork等对外暴露的函数。
JVM :站在操作系统老大的角度,JVM就是个普通程序

内核空间:只有内核能访问的空间。用户是不可能将这块内存干掉的。
用户空间:用户可以直接操作的空间。
用户态的程序要和内核态的程序打交道,需要通过系统调用。
正是因为这样的分层,使得现在的Linux,Windows非常健壮,不会轻易被程序搞崩。
Java程序员需要掌握的计算机底层知识(二):操作系统、内核、用户态与内核态、系统调用的执行过程_第3张图片

系统调用的执行过程

系统调用 是用户空间访问内核的唯一手段,除 异常陷入 外,它是内核的唯一合法入口。

系统调用表及源码链接 https://filippo.io/linux-syscall-table/

  • Linux 的系统调用,作为 C 库的一部分提供
  • 用户空间进程系统调用号 来指明执行哪个系统调用。
  • 进行系统调用的步骤:
    1. 用户空间应用程序把 系统调用号 放入 eax 寄存器中,外部参数 放在另外的 5 或 6 个寄存器中
    2. 应用程序通过 int $0x80 触发 软中断(异常),系统切换到内核态,执行 128 号异常处理程序,即 system_call() 系统调用处理程序
    3. system_call() 运行,从 eax 寄存器中得到 系统调用号,检查其有效性,然后 执行相应的系统调用
    4. 内核在执行系统调用的时候,处于 进程上下文。在进程上下文中,内核 可以休眠,并且 可以被抢占
    5. 系统调用返回 的时候,system_call() 负责 切换回用户空间,并让用户进程继续执行 int $0x80 的下一条指令

汇编示例:

# Simple program that exits and returns a status code back to the Linux kernel
./section .data # 以.为开头的名称不会被翻译为机器指令,而是作为一种汇编提示告知汇编器 ,这个形式直接被称为 “汇编指令” 或 ”伪操作“
./section .text # .text 段位保存代码, 是只读和可执行的。后面的指令都是属于 .text 段。 
.globl _start # 告诉编译器,_start 这个符号就像c程序中的main函数一样,是整个程序的入口
_start : # 是一个符号,符号在汇编中表示一个地址,可以再指令中 ,汇编程序经过汇编器的处理后, 所有的符号都被替换成为它所代表的地址值。(通俗说,c语言中的函数变量名都属于符号)
# movl 是一条数据传送指令,要求CPU内部产生一个long数字1并保存到eax寄存器中。
# 1表示在CPU内部产生 ,称为立即数,立即数在前面要加个$ ,寄存器就加个%
movl $1 ,%eax # eax 寄存器用来指定系统调用号
movl $4 ,%ebx # _ebx 的值是传给 _exit 的参数,表示退出状态。_exit 的系统调用号为1。
int $0x80 # int 指令中的立即数 0x80 是一个参数,可以用于执行系统调用

你可能感兴趣的:(#)