bigywater.tech
Java · 266

jlink:裁剪出应用需要的 Java 运行时

jlink 可以把 JDK 裁剪成只含应用所需模块的运行时。jdeps 能找出需要的模块吗?各个选项能省多少体积?裁剪之后启动时间会变吗?漏掉一个反射依赖会怎样?这篇用一个真实应用逐项测量。

350 → 30.0 MB
完整 JDK 21 → jdeps 模块 + strip-debug + zip-9 的 jlink 镜像
40 → 24 ms
jlink 镜像加 --generate-cds-archive 前后的 Hello 启动时间
163.1 MB
java.base 加 --bind-services 之后的镜像大小

jdeps 找模块

实测 · 本机执行输出
  jdeps --print-module-deps app.jar → java.base,java.logging,java.net.http 
  jdeps -s(摘要): app.jar -> java.base | app.jar -> java.logging | app.jar -> java.net.http
  完整 JDK 21 的模块数:69;目录大小 350 MB

jlink 选项与体积

实测 · 本机执行输出
  java.base 只有 base                    47.3 MB,jlink 耗时 0.5 s
  jdeps 给出的模块                          49.3 MB,jlink 耗时 0.5 s
  jdeps 的模块 + --strip-debug            44.5 MB,jlink 耗时 1.0 s
  + --compress=zip-6                   30.0 MB,jlink 耗时 1.6 s
  + --compress=zip-9                   30.0 MB,jlink 耗时 1.7 s
  不加任何选项                               49.8 MB,jlink 耗时 0.5 s
  zip-9 + --generate-cds-archive       56.6 MB,jlink 耗时 3.1 s
  对照:完整 JDK 21 350 MB;jdeps 的模块 + strip-debug + zip-9 是它的 9%
  带 --generate-cds-archive 的镜像里的 CDS 归档文件: ['classes_nocoops.jsa 13.5 MB', 'classes.jsa 13.2 MB']
  最小镜像(zip-9)的 java --list-modules: ['java.base@21.0.12.1', 'java.logging@21.0.12.1', 'java.net.http@21.0.12.1']

启动时间与缺模块

实测 · 本机执行输出
  完整 JDK 21                      Hello 启动中位 24 ms;输出 hello
  jlink 镜像(jdeps 模块,zip-9)       Hello 启动中位 40 ms;输出 hello
  jlink 镜像(zip-9 + CDS 归档)       Hello 启动中位 24 ms;输出 hello
  jlink 镜像(只有 java.base)         Hello 启动中位 36 ms;输出 hello
  只有 java.base 的镜像运行 Main(用到 java.logging 与 java.net.http): Exception in thread "main" java.lang.NoClassDefFoundError: java/util/logging/Logger …	... 1 more
  jdeps 模块的镜像运行 Main: OK | Oct 03, 2026 7:06:21 PM demo.Main main | INFO: HttpClient 创建成功:HTTP_2
  Main 通过反射 Class.forName("java.sql.DriverManager")(jdeps 看不到的依赖,镜像里没有 java.sql): Exception in thread "main" java.lang.ClassNotFoundException: java.sql.DriverManager
  同一个反射在完整 JDK 里: Oct 03, 2026 7:06:24 PM demo.Main main | INFO: HttpClient 创建成功:HTTP_2

--bind-services

实测 · 本机执行输出
  java.base 不带 --bind-services:47.3 MB,模块 1 个;带 --bind-services:163.1 MB,模块 45 个

分步演示

jlink
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS;应用是一个 HttpClient + 日志的小程序
    • 没有验证:模块化应用(module-info)的 jlink、--launcher 生成启动脚本、--vm 与 --release-info 等其它插件、跨平台的镜像(只能在目标平台上用目标平台的 JDK 生成)、jlink 镜像的安全更新方式、jdeps --multi-release 与第三方依赖(没有用到)的情况
    京ICP备2026067502号-1京公网安备11010502063487号