操作系统知识体系概览
什么是操作系统?
操作系统(Operating System, OS) 是计算机硬件与上层应用之间的**"管理者"**——它管理 CPU、内存、磁盘、网络等硬件资源,并为应用程序提供统一的运行环境。Windows、macOS、Linux、Android 都是操作系统。
对 Java 后端工程师来说,操作系统知识的重要性在于:
| 场景 | 需要的 OS 知识 |
|---|---|
| Java 并发编程 | 进程 vs 线程、上下文切换、CPU 调度 |
| JVM 内存管理 | 虚拟内存、分页、缺页中断 |
| Netty / NIO | IO 多路复用(select/poll/epoll) |
| 线上排查 | Linux 命令(top、jstack、iostat) |
| 性能调优 | CPU 调度、IO 模型、零拷贝 |
核心知识点
进程与线程——并发的基础
| 概念 | 说明 |
|---|---|
| 进程 | 操作系统资源分配的基本单位,拥有独立的地址空间 |
| 线程 | CPU 调度的基本单位,同一进程的线程共享内存 |
| 协程 | 用户态的轻量级线程,调度由程序控制(Go goroutine) |
| 虚拟线程 | Java 21 引入的轻量级线程(Project Loom) |
上下文切换是线程调度的"代价"——CPU 从一个线程切换到另一个线程时,需要保存/恢复寄存器、程序计数器、栈指针等状态。频繁的上下文切换会严重影响性能,这也是 Java 线程池要控制线程数量的原因。
死锁——并发的"噩梦"
死锁(Deadlock) 是两个或多个线程互相等待对方释放锁,导致永远阻塞。死锁的四个必要条件:
- 互斥:资源同时只能被一个线程持有
- 持有并等待:持有一个锁的同时等待另一个锁
- 不可剥夺:已获取的锁不能被强行夺走
- 循环等待:形成环形等待链
打破任一条件即可避免死锁。最常用的方法是按固定顺序加锁(打破循环等待)。
内存管理——虚拟内存与分页
操作系统通过虚拟内存让每个进程都认为自己独占了整块内存。虚拟地址通过页表映射到物理地址:
- 分页:将内存划分为固定大小的页(Page,通常 4KB),按需加载到物理内存
- 缺页中断(Page Fault):访问的页不在物理内存中,需要从磁盘加载(非常慢!)
- 页面置换算法:物理内存满时,选择哪个页换出?LRU(最近最少使用) 是最常用的策略
JVM 的堆内存就是操作系统虚拟内存的一部分。GC 时的 STW(Stop-The-World)导致的页面频繁换入换出,是 Java 应用"卡顿"的原因之一。
IO 模型——网络编程的核心
| IO 模型 | 原理 | Java 对应 |
|---|---|---|
| BIO(阻塞 IO) | 线程阻塞等待数据就绪 | java.io、ServerSocket |
| NIO(非阻塞 IO) | 轮询检查数据是否就绪 | java.nio、Channel |
| IO 多路复用 | 一个线程监听多个 fd | Selector(select/poll/epoll) |
| AIO(异步 IO) | 操作系统完成后回调通知 | AsynchronousSocketChannel |
epoll 是 Linux 下最高效的 IO 多路复用实现——Netty 在 Linux 上默认使用 epoll,Redis、Nginx 也用 epoll。epoll 相比 select/poll 的优势:不需要遍历所有 fd,只返回就绪的 fd,支持更大的并发连接数。
Linux 常用命令——线上排查必备
| 场景 | 命令 |
|---|---|
| 查看 CPU 占用 | top、htop |
| 查看内存使用 | free -h |
| 查看磁盘空间 | df -h |
| 查看进程 | `ps -ef |
| 查看端口 | netstat -tlnp、ss -tlnp |
| 查看日志 | tail -f app.log、grep 'ERROR' app.log |
| 网络诊断 | ping、curl、traceroute |
| Java 线程 | jstack <pid>(线程堆栈) |
| Java 内存 | jmap -heap <pid>(堆信息) |
学习建议
推荐学习路径
- 进程与线程 → 区别、上下文切换、协程
- 死锁 → 四个条件、排查方法
- 内存管理 → 虚拟内存、分页、页面置换
- IO 模型 → BIO/NIO/IO 多路复用/AIO
- CPU 调度 → 调度算法
- Linux 命令 → 线上排查实战