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