JDK Upgrade Journey: From JDK 8 to JDK 17 with Performance Gains and GC Tuning
This article documents a comprehensive migration from JDK 8 to JDK 17, detailing new language and JVM features, step‑by‑step upgrade procedures, Maven and SpringBoot version changes, performance benchmarking, and ZGC‑based garbage‑collection tuning to dramatically reduce pause times.
Since its release in 2014, JDK 8 has been a cornerstone for many Java projects, but after nine years the JDK ecosystem has introduced numerous enhancements that merit an upgrade.
New Features Overview
G1 (JEP 248, 307, 344, 345, 346) – high‑performance GC with pause‑time targets and NUMA awareness.
ZGC (JEP 333, 376, 377) – sub‑millisecond pause GC.
Concurrent API updates (JEP 266) – reactive streams and CompletableFuture improvements.
Collection factory methods (JEP 269) – Guava‑like convenient factories.
New HTTP client (JEP 321) – async, WebSocket, reactive support.
Enhanced NPE messages (JEP 358) – method location in stack traces.
Pattern matching for instanceof (JEP 394).
Record classes (JEP 395) – immutable data carriers.
Switch expression enhancements (JEP 361).
Text blocks (JEP 378) – multi‑line string literals.
Sealed classes (JEP 409) – restricted inheritance.
Various JVM and data‑structure optimisations.
Upgrade Evaluation Criteria
The upgrade must resolve existing performance bottlenecks.
Comprehensive regression suite (unit tests, automated integration tests) must be available.
Technical debt should be minimal to avoid migration obstacles.
The responsible engineers must understand the system’s core logic and its middleware dependencies.
The chosen target is a settlement‑page service built on JDK 8, SpringBoot 2.0.8, and internal middlewares (UMP, SGM, DUCC, CDS, JMQ, JSF, R2M).
Upgrade Steps
1. Update Maven compiler version and Java source level:
<java.version>11</java.version> <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${java.version}</release>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>2. Add missing Java EE modules removed in JDK 11:
<!-- JAVAX -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
…3. Upgrade SpringBoot to a version that supports JDK 17 (Spring 5.3, SpringBoot 2.7). Adjust configuration properties such as spring.main.allow-bean-definition-overriding=true and migrate spring.factories entries to META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports .
4. Update internal middleware versions (e.g., UMP 20221231.1, JMQ 2.3.3‑RC2, JSF 1.7.6‑HOTFIX‑T2) and ensure they open required JDK modules via --add-opens flags.
5. Adjust JVM launch parameters for ZGC and large‑heap tuning:
JAVA_DEBUG_OPTS=" -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000 " JAVA_GC_LOG_OPTS=" -Xlog:gc*:file=/export/logs/gc.log:time,tid,tags:filecount=10:filesize=10m " JAVA_MEM_OPTS=" -server -Xmx12g -Xms12g -XX:MaxMetaspaceSize=256m -XX:+UseZGC -XX:ZAllocationSpikeTolerance=3 -XX:ParallelGCThreads=8 -XX:CICompilerCount=3 "Full launch command (truncated for brevity):
-javaagent:/export/package/sgm-probe-java/sgm-probe-5.9.5-product/sgm-agent-5.9.5.jar … -XX:+UseZGC -XX:ZAllocationSpikeTolerance=3 … --add-opens=java.base/sun.net.util=ALL-UNNAMED …Performance Results
Version
Throughput
Avg Latency
Max Latency
JDK 8 G1
99.966%
35.7 ms
120 ms
JDK 17 ZGC
99.999%
0.0254 ms
0.106 ms
The upgrade yields a 0.01 % throughput increase, a 1 405‑fold reduction in average GC pause, and a 1 132‑fold reduction in maximum pause.
GC Tuning (ZGC)
ZGC targets sub‑millisecond pauses for heap sizes up to 16 TB. No extensive tuning is required; the primary adjustment is allocating a sufficiently large heap (e.g., -Xmx12g -Xms12g ) and optionally increasing -XX:ZAllocationSpikeTolerance to handle traffic spikes.
Additional tweaks include raising CICompilerCount and ParallelGCThreads to improve JIT compilation and parallel GC phases, and optionally enabling Large Pages where the deployment environment permits.
Conclusion
After migrating to JDK 17, adopting ZGC, and updating SpringBoot and middleware dependencies, the service now runs with negligible GC pauses, stable throughput, and has passed extensive regression, load‑testing, and production‑traffic validation cycles.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.