操作系统底层

计算机模型

计算机五大核心组成

操作系统硬件结构图

CPU内部结构

CPU缓存结构

CPU缓存结构

CPU为了提升执行效率,减少CPU与内存的交互,一般在CPU上集成了多级缓存架构,常见的为三级缓存结构,存储器存储空间大小内存>L3>L2>L1>寄存器,存储器速度快慢排序寄存器>L1>L2>L3>内存

  • L1 Cache,分为数据缓存和指令缓存,逻辑核独占
  • L2 Cache,物理核独占,逻辑核共享
  • L3 Cache,所有物理核共享

缓存是由最小的存储区块缓存行cacheline组成,缓存行大小通常为64byteL1缓存大小是512kb,则L1里有512 * 1024/64个缓存行。

在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部性原理

时间局部性(Temporal Locality):若一个信息项正在被访问,则近期很可能还会被再次访问,如循环、递归、方法的反复调用等。

空间局部性(Spatial Locality):若一个存储器的位置被引用,则将来其附近位置也会被引用,如顺序执行的代码、连续创建的两个对象、数组等。

带有高速缓存的CPU执行计算的流程:程序以及数据被加载到主内存,指令和数据被加载到CPU的高速缓存,CPU执行指令,把结果写到高速缓存,高速缓存中的数据写回主内存;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class TwoDimensionalArraySum {
private static final int RUNS = 100;
private static final int DIMENSION_1 = 1024 * 1024;
private static final int DIMENSION_2 = 6;
private static long[][] longs;

public static void main(String[] args) throws Exception {
longs = new long[DIMENSION_1][];
for (int i = 0; i < DIMENSION_1; i++) {
longs[i] = new long[DIMENSION_2];
for (int j = 0; j < DIMENSION_2; j++) {
longs[i][j] = 1L;
}
}
System.out.println("Array初始化完毕....");
long sum = 0L;
long start = System.currentTimeMillis();
for (int r = 0; r < RUNS; r++) {
for (int i = 0; i < DIMENSION_1; i++) {//DIMENSION_1=1024*1024
for (int j = 0; j < DIMENSION_2; j++) {//6
sum += longs[i][j];
}
}
}
System.out.println("spend time1:" + (System.currentTimeMillis() - start));
System.out.println("sum1:" + sum);

sum = 0L;
start = System.currentTimeMillis();
for (int r = 0; r < RUNS; r++) {
for (int j = 0; j < DIMENSION_2; j++) {//6
for (int i = 0; i < DIMENSION_1; i++) {//1024*1024
sum += longs[i][j];
}
}
}
System.out.println("spend time2:" + (System.currentTimeMillis() - start));
System.out.println("sum2:" + sum);
}
}
1
2
3
4
5
Array初始化完毕....
spend time1:1428
sum1:629145600
spend time2:4371
sum2:629145600

CPU运行安全等级

CPU有4个运行级别从高到低分别为:ring0,ring1,ring2,ring3;Linux与Windows只用到ring0、ring3,操作系统内部程序指令通常运行在ring0级别,第三方程序运行在ring3级别,若第三方程序要调用操作系统内部函数功能,必须切换CPU运行状态即从ring3切换到ring0;因为CPU要切换运行状态,所以JVM创建线程,线程阻塞唤醒是重型操作

JVM创建线程CPU的工作过程,CPUring3切换ring0创建线程,创建完毕,CPUring0切换回ring3,线程执行JVM程序,线程执行完毕,销毁还得切会ring0

执行空间保护

操作系统有用户空间内核空间两个概念,目的也是为了做到程序运行安全隔离与稳定,用户程序运行在用户方式下,系统调用运行在内核方式下。在这两种方式下所用的堆栈不一样:用户方式下用的是一般的堆栈,即用户空间的堆栈,内核方式下用的是固定大小的堆栈内核空间的堆栈,一般为一个内存页的大小,即每个进程与线程其实有两个堆栈,分别运行于用户态内核态

执行空间保护

CPU调度的基本单位线程,划分为内核线程模型(KLT),用户线程模型(ULT) ,JVM使用的是内核线程模型

内核线程模型(KLT)系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快

用户线程模型(ULT):用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程不需要用户态/内核态切换,速度快,内核对ULT无感知,线程阻塞则进程阻塞。

线程上下文切换

虚拟机指令集架构

虚拟机指令集架构主要分两种:栈指令集架构寄存器指令集架构,Java是栈指令集架构,Python、Go是寄存器指令架构。

栈指令集架构

  1. 设计和实现更简单,适用于资源受限的系统;
  2. 避开了寄存器的分配难题:使用零地址指令方式分配;
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈指令集更小,编译器容易实现;
  4. 不需要硬件支持可移植性更好,更好实现跨平台。

寄存器指令集架构

  1. 典型的应用是x86的二进制指令集:比如传统的PC以及Android的Davlik虚拟机。
  2. 指令集架构则完全依赖硬件,可移植性差。
  3. 性能优秀和执行更高效。
  4. 花费更少的指令去完成一项操作。
  5. 在大部分情况下,基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主。