文档目录
Kotlin/JVM 性能基础
本章定位:本章不教工具,只解决一个问题——为什么你的测量结果可能是假的。学完你才有资格谈「优化」。
前置知识:第 0 章(0.9 从 C++ 到 JVM) 预计总时长:约 4 小时(阅读 2.5 小时 + Lab 2 约 1.5 小时) 配套代码:docs/code/02-jvm-performance-basics/
一、本章要回答的七个问题
- 为什么「同一个方法」在前 100 次调用和第一万次调用时,性能能差 5 倍?(第 1 节)
- 为什么代码里加一种「类型」就可能让性能掉一半?(第 2 节)
- 为什么你写的基准测试测出了「0.2 纳秒」这种物理上不可能的数字?(第 3 节)
- 怎么用数据(而不是拍脑袋)判断「预热够了」?(第 4 节)
- 为什么「堆越大越好」是错的?该看哪个指标?(第 5 节)
- 加了 8 个线程,吞吐反而下降了,为什么?(第 6 节)
- 为什么把数据库查询放进协程里,整个服务会一起卡住?(第 7 节)
二、为什么这一章排在所有工具前面
第 0 章讲了观念,但观念需要机制来支撑。举三个例子:
| 第 0 章的结论 | 本章补上的机制 |
|---|---|
| 「必须预热」 | 分层编译:解释执行 → C1 → C2,每一级阈值不同(第 1 节) |
| 「不共享优于聪明地共享」 | 上下文切换、伪共享、安全点的真实成本(第 6 节) |
| 「协程便宜但有限」 | Dispatchers.Default 的并行度 = CPU 核数,阻塞调用会饿死它(第 7 节) |
如果先学工具(k6、火焰图),你会用它们产出一堆漂亮的假数据,并在错误的方向上投入大量时间。 顺序不能反。
三、小节地图
| 节 | 标题 | 一句话内容 | 时长 | 要动手 |
|---|---|---|---|---|
| 1 | 四种执行形态:为什么必须预热 | 解释执行 → C1 → C2,性能随调用次数台阶式提升 | 25 min | ✅ 实验 |
| 2 | JIT 的三大优化与去优化 | 内联、逃逸分析、以及「假设被打破」的代价 | 25 min | ✅ 实验 |
| 3 | 微基准四大陷阱 | DCE、常量折叠、分支预测、未消费结果 | 30 min | ✅ 实验 |
| 4 | 预热、稳态与冷启动 | 同一份代码在三个时间尺度上是三个系统 | 25 min | ✅ 实验 |
| 5 | 内存与 GC:分配速率才是关键 | 「堆有多大」不如「每秒产生多少垃圾」 | 30 min | ✅ 实验 |
| 6 | 并发原语成本与伪共享 | 锁、CAS、上下文切换的量级;加线程为何变慢 | 25 min | ✅ 实验 |
| 7 | 协程的真实开销模型 | 调度器有上限;阻塞调用是头号杀手 | 30 min | ✅ 实验 |
| 8 | JMH 与 kotlinx-benchmark | 标准化基准工具,以及怎么读它的输出 | 30 min | ✅ 配置 |
| 9 | Lab 2:三份基准与一个坏基准 | 亲手对比三种测量方式的可信度 | 90 min | ✅ 实验 |
四、本章的产出物
- 三份基准:裸计时 / JMH / kotlinx-benchmark,对同一个算法做测量,并解释数字差异。
- 一个坏基准:故意构造被 JIT 优化掉的基准,并解释它为什么假。
- 一张「并发成本表」:无竞争锁、CAS、线程创建、上下文切换、协程挂起,各自是你自己机器上测出的量级。
- 一次调度器饥饿实验:观察到「阻塞调用污染 Default 调度器」的全过程。
五、学完本章的验收标准
- 能解释为什么「第一次调用」和「第一万次调用」不是同一段代码。
- 能说出「去优化」是什么,以及什么样的代码容易触发它。
- 能识别一个基准是否踩了四大陷阱,并说出怎么修。
- 能用数据(不是感觉)判断稳态是否到达。
- 能说出 JVM 上比「堆占用」更重要的内存指标是什么。
- 能解释「线程越多吞吐越高」为什么是错的。
- 能说出
Dispatchers.Default和Dispatchers.IO的并行度上限,以及阻塞调用的后果。
六、一个提醒
本章的代码都是可以运行的,但请记住:
它们的数字来自你的开发机,有后台进程干扰、没有 fork 隔离、没有严格预热。这些数字只用于量级对比和机制验证,不能用于任何工程决策。
真正可信的基准从第 8 节(JMH)开始。前面 7 节的价值在于:让你在读到 JMH 的规则时,知道每一条规则在防什么。
本节目录
- 四种执行形态 2.1 四种执行形态:为什么必须预热 上一节:无 | 下一节:2.2 JIT 的三大优化与去优化 配套代码 …
- JIT 的三大优化与去优化 2.2 JIT 的三大优化与去优化 上一节:2.1 四种执行形态 | 下一节:2.3 微基准四大陷阱 配套代码 …
- 微基准四大陷阱 2.3 微基准四大陷阱 上一节:2.2 JIT 的三大优化与去优化 | 下一节:2.4 预热、稳态与冷启动 配套代码 …
- 预热、稳态与冷启动 2.4 预热、稳态与冷启动 上一节:2.3 微基准四大陷阱 | 下一节:2.5 内存与 GC 配套代码 …
- 内存与 GC 2.5 内存与 GC:分配速率才是关键 上一节:2.4 预热、稳态与冷启动 | 下一节:2.6 并发原语成本与伪共享 配套代码 …
- 并发原语成本与伪共享 2.6 并发原语成本与伪共享 上一节:2.5 内存与 GC | 下一节:2.7 协程的真实开销模型 配套代码 …
- 协程的真实开销模型 2.7 协程的真实开销模型 上一节:2.6 并发原语成本与伪共享 | 下一节:2.8 JMH 与 kotlinx-benchmark 配套代码 …
- JMH 与 kotlinx-benchmark 2.8 JMH 与 kotlinx-benchmark:标准化的基准工具 上一节:2.7 协程的真实开销模型 | 下一节:2.9 Lab 2 配套代码 …
- Lab 2 2.9 Lab 2:三份基准与一个坏基准 上一节:2.8 JMH 与 kotlinx-benchmark | 下一节:第 3 章 测试分层 配套代码 …