# 5. jlink: 133 MB smaller, 15 metrics quieter [← 4. Buildpacks](04-buildpacks.md) · [Index](../README.md) · Next: [6. AOT cache →](06-aot-cache.md) [`Dockerfile.jlink-distroless`](../docker/Dockerfile.jlink-distroless) asks `jdeps` which JDK modules the application needs and builds a runtime with only those: ```bash jdeps --ignore-missing-deps -q --recursive --multi-release 25 --print-module-deps \ --class-path 'extracted/dependencies/lib/*' extracted/application/application.jar ``` It chose 18 modules ([`jlink-metrics.txt`](output/jlink-metrics.txt)) - including `java.desktop`, because Spring uses `java.beans`. On `distroless/java-base` the image is **119 MB** on disk against 252 MB for distroless with the full JRE. ## It runs. It is also missing something. The jdeps-only image starts, serves requests and passes its health check. Its startup log has two warnings: ``` i.m.c.i.binder.jvm.JvmGcMetrics : GC notifications will not be available because com.sun.management.GarbageCollectionNotificationInfo is not present i.m.c.i.binder.jvm.JvmGcMetrics : GC notifications will not be available because no GarbageCollectorMXBean of the JVM provides any. GCs=[G1 Young Generation, G1 Concurrent GC, G1 Old Generation] ``` and `/actuator/prometheus` exports 46 metric names instead of 61. Gone: `jvm_gc_pause_seconds_*`, `jvm_gc_memory_allocated_bytes_total`, `jvm_gc_live_data_size_bytes`, `process_cpu_usage`, `system_cpu_usage`, `process_files_open_files` and more - 15 in total. `com.sun.management.*` lives in the `jdk.management` module, and Micrometer touches it reflectively, which `jdeps` cannot see. Nothing fails; the GC and CPU panels of your dashboard just go flat after the image switch. The Dockerfile now adds it by default: ```dockerfile ARG EXTRA_MODULES="jdk.management" ``` With it, the only difference left is `jvm_gc_concurrent_phase_time_*`, which Micrometer registers lazily inside its GC notification listener - it appears after the first G1 concurrent cycle, which may or may not have happened a few seconds after startup, in either image. The general rule: diff the metric names, not just the health check, before shipping a jlink image. Other modules commonly needed only reflectively are `jdk.crypto.cryptoki` (PKCS#11), `jdk.localedata` (non-English locale data) and `jdk.naming.dns` (DNS lookups through JNDI).