bigywater.tech
Java · 275

Java 启动优化:把冷启动时间拆成可测阶段

启动慢不能凭感觉优化。这篇用一个真实的 Jackson + HttpServer 小程序,把冷启动拆成 JVM 启动、应用初始化、第一次请求三段,再逐个测试常见的启动选项,看每个选项到底省了多少。

173 → 102 ms
启动到 READY:默认 → AppCDS
17.0 ms
JVM 启动到 main 入口(应用初始化 140.0 ms)
没有变化
-XX:+UseSerialGC 与 -XX:-UsePerfData 对这个程序的启动时间的影响

冷启动的阶段

实测 · 本机执行输出
  默认配置(10 次去掉前 2 次,中位):进程启动到收到 READY 173 ms;到第一次请求返回 192 ms;其中 JVM 启动到 main 入口(RuntimeMXBean.getStartTime 到 main)约 17.0 ms,main 里创建 ObjectMapper、解析 JSON、启动 HttpServer 用了 140.0 ms
  对照 java -version(只初始化 JVM 就退出)中位 25 ms
  加载的类共 2196 个:CDS 共享归档 1157,jrt(JDK 模块文件)361,jar 文件(应用与 Jackson)567

启动选项逐个试

实测 · 本机执行输出
  默认                                 到 READY   173 ms,到首次请求返回   192 ms(main 里 140.5 ms)
  -XX:TieredStopAtLevel=1(只用 C1)     到 READY   155 ms,到首次请求返回   174 ms(main 里 124.5 ms)
  -XX:+UseSerialGC                   到 READY   172 ms,到首次请求返回   191 ms(main 里 140.0 ms)
  -XX:-UsePerfData                   到 READY   171 ms,到首次请求返回   191 ms(main 里 140.0 ms)
  -Xshare:off(关掉 CDS)                到 READY   202 ms,到首次请求返回   224 ms(main 里 153.0 ms)
  -XX:+AutoCreateSharedArchive(AppCDS) 到 READY   102 ms,到首次请求返回   117 ms(main 里 68.5 ms)
  SerialGC + C1 + AppCDS             到 READY    90 ms,到首次请求返回   104 ms(main 里 59.0 ms)

类加载的构成

实测 · 本机执行输出
  按来源: {'CDS 共享归档': 1157, 'jrt(JDK 模块文件)': 361, 'jar 文件(Jackson 与应用)': 567, '其它': 111}
  类数量最多的包前缀(前 8): [('com.fasterxml.jackson.databind', 424), ('java.lang.invoke', 185), ('java.util', 177), ('java.lang', 141), ('com.fasterxml.jackson.core', 94), ('java.util.stream', 57), ('java.lang.reflect', 55), ('java.util.concurrent', 55)]
  com.fasterxml(Jackson)的类 567 个,占全部 2196 个的 25%;JDK 内部(sun.*、jdk.*、java.*)的类 1596 个

main 里的耗时

实测 · 本机执行输出
  new ObjectMapper 84 ms;第一次 readValue(含反射与序列化器构建)30 ms;第一次 writeValueAsString 5 ms;HttpServer.create 15 ms;createContext+start 0 ms
  第二次 readValue 59 μs
  -XX:TieredStopAtLevel=1 下: new ObjectMapper 75 ms;第一次 readValue(含反射与序列化器构建)26 ms;第一次 writeValueAsString 5 ms;HttpServer.create 14 ms;createContext+start 0 ms ;第二次 readValue 83 μs

分步演示

Java 启动优化
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS 10 核;应用依赖 jackson-databind 2.18.2 与 JDK 自带 HttpServer
    • 没有验证:Spring 等框架的启动、native-image 与 CRaC 等方案、-Xshare 的静态归档(-XX:SharedClassListFile)、懒加载与并行初始化的收益、JIT 编译线程数的调整、磁盘冷缓存下的首次启动(每次测量前文件都在页缓存里);耗时是单机少量测量
    京ICP备2026067502号-1京公网安备11010502063487号