Java底层操作系统
Hz488 人气:0一、现代计算机硬件结构
核心部分: CPU、内存
1.CPU内部结构
- 控制单元: 整个 CPU 的指挥控制中心
- 运算单元: 运算器核心,执行算术运算与逻辑运算。运算器接收控制单元的指令而执行动作
- 存储单元: CPU 中暂时存储数据的地方,包括 CPU 片内缓存 Cache 和 寄存器组
1.1.CPU缓存结构
现代 CPU 为了提升执行效率,减少 CPU 与内存的交互(交互影响 CPU 效率),一般在 CPU上集成了多级缓存架构,常见的为三级缓存结构
- L1 Cache,分为数据缓存和指令缓存,逻辑核独占
- L2 Cache,物理核独占,逻辑核共享
- L3 Cache,所有物理核共享
此机器的三级缓存架构如下图:L1 Cache又分为两种,指令存储单元(存指令),和逻辑存储单元(存逻辑)。理论上一台机器可以有多个 CPU,由插槽决定,一个 CPU 又有多核,一个核又可以由多个逻辑处理器。
寄存器是 CPU 内部元件,读写速度非常快。 CPU 读取数据只会从寄存器中去取,每个 CPU 都有一个独有的寄存器,其他 CPU 无法访问。采用寄存器,可以减少 CPU 访问内存的次数,从而提高了 CPU 的工作速度。
越靠近 CPU 读取速度越快,摩尔定律中,CPU 以每18个月翻一番的速度在发展,而内存和硬盘的发展速度远远跟不上。为了解决 CPU 运算速度和 I\O 速度不匹配的问题,CPU 开始被内置了少量的高速缓存 Lx Cache(CPU空间有限,存储元件大小受限)。
- 存储器存储空间大小: 内存 > L3 Cache > L2 Cache > L1 Cache > 寄存器
- 存储器读取速度快慢: 寄存器 > L1 Cache > L2 Cache > L3 Cache > 内存
- 缓存是由最小的存储区块--- 缓存行(CacheLine) 组成,缓存行大小通常为64byte。我的机器L1的缓存大小时512K,则由512 * 1024/64个缓存行组成。
CPU读取存储器数据过程: CPU 仅能直接从寄存器中获取数据。 假设数据 x = 0 在内存中,则它的取值过程如下:
判断寄存器中是否存在
不存在则遍历L1 Cache 看是否存在,不存在遍历L2 Cache,L2 Cache 中没有,遍历L3 Cache。中间过程存在,则会把 Cache 行锁住,拷贝到上一级,直至到寄存器。
Cache 中没有则区内存中找,先通知内存控制器占用总线带宽,通知内存加锁,发起内存读请求,等待回应,回应数据拷贝到L3 Cache。 注意:整个过程加锁直至到CPU才会解开
局部性原理:在CPU访问存储设备时,无论是存取数据还是存取指令,都趋于聚集在一片连续的区域中。
这种局部性原理又有两种:
- 时间局部性(Temporal Locality): 如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。 比如循环、递归、方法的反复调用等。
- 空间局部性(Spatial Locality): 如果一个存储器的位置被引用,那么将来他附近的位置也会被引用。 比如顺序执行的代码、连续创建的两个对象、数组等。
空间局部性的例子: 一个很大的二维数组,累加求和一行一行加会比一列一列累加快很多。在CPU 在内存中读取数据时会将附件的数据都读进去。
1.2.CPU运行安全等级
CPU被划分为 4 个运行级别:
- ring0 内核态
- ring1
- ring2
- ring3 用户态
Linux 和 Windows 都只用到了两个级别:ring0、ring3,操作系统内部内部程序指令通常运行在 ring0 级别,操作系统以外的第三方程序运行在 ring3 级别,第三方程序如果要调用操作系统内部函数功能,由于运行安全级别不够,必须切换CPU运行状态,从 ring3 切换到 ring0, 然后执行系统函数,创建线程,线程阻塞唤醒是重型操作,因为CPU要切换运行状态。
JVM 创建线程是 CPU 的流程:
- 第一步:CPU 从 ring3 切换 ring0 创建线程
- 第二步: 创建完毕,CPU从 ring0 切回 ring3
- 第三步: 线程执行JVM程序
- 第四步: 线程执行完毕,销毁切回 ring0
- 第五步: 线程销毁,切回 ring3
2.操作系统内存管理
为了使程序运行安全隔离与稳定,操作系统有用户空间
与内核空间
两个概念。以 32位操作系统4G大小的内存空间为例:
Linux 为内核代码和数据结构预留了几个页框,这些页永远不会被转出到磁盘上(4GB内存空间,用户程序可使用3GB)。如图绿色部分的线性地址可由用户代码和内核代码进行引用(即用户空间)。黄色部分的线性地址只能由内核代码进行访问(即内核空间)。
进程与线程只能运行在用户方式(usermode) 或 内核方式(kernelmode) 下。用户程序运行在用户方式下,而系统调用运行在内核方式下。
用户方式下使用一般的堆栈(用户空间的堆栈),内核方式下使用固定大小的堆栈(内核空间的堆栈,一般为一个内存页的大小),即每个进程与线程其实有两个堆栈,分别运行与用户态与内核态。
CPU调度的基本单位线程,也划分为:
- 内核线程模型(KLT): Java使用,内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快。
- 用户线程模型(ULT): 不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/内核态切换,速度快。内核对ULT无感知,线程阻塞则进程(包括它的所有线程)阻塞
线程都有两个堆栈,一个在用户空间,一个在内核空间。阻塞、创建、杀死线程将抛弃用户空间的堆栈,转移到内核空间,执行完毕后再转移到用户空间。
3.进程与线程
进程: 操作系统资源分配的最小单位,例如:启动一个 Java 程序,操作系统就会创建一个Java 进程,进程中可以包含多个线程。
线程: 操作系统调度CPU的最小单元,线程都拥有各自的计数器、堆栈和局部变量等属性, 并且能够访问共享的内存变量。CPU 在这些线程上高速切换,让使用者感觉到这些线程在同时执行(并发)。
线程上下切换: 保存上一个线程运行的中间状态,执行下一个线程
- 串行: 时间上不可重叠,前一个任务没完成,下一个任务只能等待
- 并行: 时间上是重叠的,两个任务在同一时刻互不干扰的同时执行
- 并发: 运行两个任务彼此干扰,同一时间点,只有一个任务执行,交替执行
加载全部内容