【前言】
本章并不详细介绍关于计算机底层的东西,由于Java开发岗并不和硬件等底层的东西打交道,所以这里仅讲解部分Java中能用到的知识点,至于更深的东西,有兴趣者可自行学习
1.硬件物理连接全景图
此图中,CPU边界以上是为CPU的核,CPU中有多个核,这些核结构相同,与外部的连接也相同。此处仅列举出一个核做演示。
2.CPU:执行你Java字节码的“大脑”
CPU是电脑里真正干活的部件。它内部有核心(干活的人)、寄存器(手边的小抽屉)、缓存(桌上的资料夹)。
2.1 CPU内部结构
| 组件 | 作用 | 对Java开发的意义 |
|---|---|---|
| 运算器 (ALU) | 执行加减乘除、位运算 | i++、a & b最终在这里执行 |
| 控制器 (CU) | 取指令、译码、控制执行流程 | 决定程序执行顺序,分支预测失败会拖慢速度 |
| 寄存器 | CPU内部最快存储,容量极小 | 变量最终被加载到这里参与运算;JIT会尽量把热变量放寄存器 |
| L1缓存 | 每核私有,32-64KB | 存放最近执行的指令和数据 |
| L2缓存 | 每核私有,256KB-1MB | L1未命中时查L2 |
| L3缓存 | 多核共享,8-32MB+ | 多线程共享数据;伪共享发生在这里 |
| 内存控制器 | 管理内存读写 | 决定内存带宽和延迟 |
| PCIe控制器 | 连接网卡、硬盘 | 决定外设吞吐 |
2.2 核心、线程与超线程
物理核心是真正独立干活的单元。超线程是让一个物理核心“假装”成两个,让两个线程交替使用核心的运算资源,提升利用率但不会翻倍。
线程:线程就是一段代码的执行流,可以理解为“拿着指令的工人”,最终每个线程会被分配给逻辑处理器。成千上万的线程就是操作系统分配给这些个逻辑处理器的。
物理核心:独立运算单元。
超线程:一个物理核模拟两个逻辑处理器(这样的核我们称之为“大核”,“小核”就是一个内核对应一个逻辑处理器,不同cpu厂商对于大小核的制造不同),共享ALU和L1/L2,但有独立寄存器组。
2.3 CPU缓存行 (Cache Line)
CPU读内存不是一个个字节读,而是一口气读64字节(一个缓存行)。这就带来一个坑:两个线程改同一行里的不同变量,会互相干扰,叫“伪共享”。
缓存行:CPU缓存读写的最小单位,通常64字节。
伪共享 (False Sharing):两个线程分别修改同一缓存行里的不同变量,导致缓存行在两个核心间来回失效同步,性能骤降
2.4 上下文切换
操作系统从一个线程切到另一个线程,要保存当前寄存器状态、加载新线程状态,这个搬运过程就是上下文切换,它不干业务活,纯开销。
一次切换约几微秒(几千到上万CPU周期)。每秒几万次切换,CPU大量时间花在切换上。
3.CPU寄存器组详解 and 指令加载实例
寄存器是CPU手边的小抽屉,分好几组,各管一摊。下面用一条加法指令,让你看到数据怎么从内存“爬”到寄存器里算完再爬回去。
3.1 寄存器分组(了解即可,不需要记忆)
| 组别 | 名称 | 作用 | Java对应 |
|---|---|---|---|
| 通用寄存器 | RAX, RBX, RCX, RDX | 累加、基址、计数、数据 | 局部变量、返回值、中间结果 |
| 指针寄存器 | RSP, RBP | 栈指针、基址指针 | 指向当前线程栈帧 |
| 变址寄存器 | RSI, RDI | 源/目的变址 | 字符串操作、数组遍历索引 |
| 指令指针 | RIP | 指向下一条指令地址 | 最关键,决定程序执行到哪 |
| 标志寄存器 | RFLAGS | 记录运算状态(零、溢出、进位) | if判断依赖它 |
3.2 实例:int c = a + b 的硬件执行过程
这里不进行具体的寄存器的介绍,这不是我们需要过度关注的。我们采取更为通俗一点的方法介绍,让大家有所体会。
4.内存(DRAM):Java对象的家
这里说的内存和硬盘的速度,主要指的是IO的速度,也就是input输入 /output输出 的速度
4.1 内存是什么?
1. 它是 CPU 的“工作台”:CPU 算得极快(1 秒能算几十亿次),但硬盘太慢了。CPU 不可能直接去硬盘里翻数据。所以,程序要运行,必须先把数据从硬盘搬到“内存”里,CPU 直接跟内存打交道。
2. 它是你 Java 对象的“家”:你在代码里 new 出来的每一个对象,以及方法里的局部变量等等,运行时都实实在在住在这块物理内存条上。
3. 它的致命弱点:断电就死:它靠电来维持数据(电容、所以叫“动态”),只要一停电或者重启,里面的东西瞬间灰飞烟灭
4.2 内存和硬盘的区别
1. 容量和价格:硬盘(SSD/机械硬盘)通常是几百 G 到几 T,便宜且量大;内存通常是 8G、16G、32G(服务器可能 128G),贵且量小。
2. 速度天壤之别:如果内存读一次数据需要 100 纳秒,硬盘读一次可能需要 10 毫秒(甚至几十毫秒)。硬盘比内存慢了大概十万倍。
5.磁盘(SSD/HDD):持久化与I/O瓶颈
磁盘是数据最终落地的仓库,也是后端性能的重灾区。核心要记住:顺序I/O远快于随机I/O。
HDD vs SSD(了解即可)
| 特性 | HDD(机械硬盘) | SSD(固态硬盘) |
|---|---|---|
| 原理 | 磁头+旋转盘片 | NAND闪存电子读写 |
| 随机I/O | 极慢(毫秒级,寻道) | 快(微秒级) |
| 顺序I/O | 100-200MB/s | 500MB/s-数GB/s |
| 对Java的意义 | 数据库/日志绝不放HDD | 数据库/日志/类文件都放SSD |
机械硬盘:
固态硬盘:
6.网卡(NIC)
网卡是请求的入口和出口。一个网络包到达你的Java代码,要经历“网卡收信号→DMA写内存→中断CPU→内核协议栈解包→唤醒Java线程→拷贝到用户空间”这一长串。高性能的秘密就藏在减少搬运和减少中断里。
7.总线:连接一切的“高速公路”
总线就是主板上的数据公路。CPU到内存有内存总线,CPU到网卡/SSD有PCIe总线,多路CPU之间有QPI/UPI。路宽(带宽)和路况(延迟)决定整体性能上限。
| 总线 | 连接 | 特点 |
|---|---|---|
| 内存总线 | CPU↔DRAM | 极快,几十GB/s |
| PCIe总线 | CPU↔网卡/SSD/GPU | 串行点对点,PCIe 4.0 x16约32GB/s |
| QPI/UPI | CPU↔CPU(多路) | 处理器互联,NUMA基础 |
| DMI | CPU↔芯片组(南桥) | 连USB、SATA等低速外设 |
8.完整链路回顾:int c = a + b 在硬件上发生了什么
1. `RIP`指向指令地址 → 从“L1指令缓存”取指令。
2. 译码 → 需读变量a、b。
3. a、b从“DRAM”(可能已缓存在L3/L2/L1)加载到“RAX等寄存器”。
4. “ALU”执行加法,结果写回寄存器。
5. 结果写回内存(栈)。