Files
zgc-jdk25-benchmarks/jdk28-zgc

jdk28-zgc — what ZGC startup and heap sizing look like today, and what JEP 545 / 546 propose

Companion module for the ankurm.com post ZGC in JDK 28: Adaptive Heap Sizing (JEP 546) and Faster Startup (JEP 545). There is no docs/ folder: this README and the captured files in output/ are the documentation.

The honest status

On 12 October 2026 both JEPs show "Proposed to Target" for release 28 on openjdk.org. Neither is integrated. output/01-flag-probe.txt proves it: -XX:+ZAdaptiveHeapSizing is an Unrecognized VM option on JDK 25.0.4.1, Temurin 27+35 and OpenJDK 28-ea+19. So this module does not benchmark the proposed features. It measures the baseline they are meant to improve, on three JDKs, so you can rerun it the day a build contains the flag.

Versions

Component Version
JDK 25 Temurin 25.0.4.1+1 (LTS)
JDK 27 Temurin 27+35 (GA 2026-09-15)
JDK 28 OpenJDK 28-ea+19 (jdk.java.net build 19, 2026-10-08)
Spring Boot 4.1.1 (spring-boot-starter-webmvc)
Machine 2 vCPU, 8 GB RAM Linux sandbox (a small box: absolute numbers are illustrative)

Quick start

mvn -B -DskipTests package                      # build with any JDK 25+
export J25=/path/to/jdk-25 J27=/path/to/jdk-27 J28=/path/to/jdk-28-ea
scripts/run-all.sh                              # regenerates everything in output/
RUNS=10 scripts/run-all.sh                      # more runs, tighter medians
scripts/startup.sh $J28 "my label" 5 -XX:+UseZGC -Xms1g

Files

File What it is
src/main/java/com/ankurm/zgc/DemoApplication.java One server: /hello allocates 16 KB, /heap reports committed and max heap
scripts/startup.sh Wall-clock ms from process start to first HTTP 200, repeated, with min/median/max
scripts/warmup.sh + scripts/Warmup.java 20,000 requests, 4 threads, timing each batch of 2,000; client is always JDK 25
scripts/run-all.sh Runs all three experiments

Results (median of 5 runs, milliseconds to first response)

Config JDK 25 JDK 27 JDK 28-ea
ZGC defaults 3439 3421 3420
-Xms64m 3299 3276 3350
-Xms1g 3478 3275 3642
-Xms3g 3836 3618 3803
-Xms3g -XX:+AlwaysPreTouch 4834 4560 5010

Raw per-run lines: output/02-startup-vs-xms.txt.

Warmup, total ms for the first 20,000 requests (first 2,000 in brackets):

Config JDK 25 JDK 28-ea
defaults 9708 (2678) 9912 (2567)
-Xms3g 9193 (2606) 9608 (2431)
-Xms64m 9247 (2442) 9893 (2590)

Raw: output/03-warmup.txt.

What the numbers say, and do not say

  • A bigger initial heap costs startup time, and AlwaysPreTouch costs the most (about +1.2 s to +1.6 s on a 3 GB heap here).
  • On this small box the effect is a fraction of Spring Boot's own ~3.3 s startup. JEP 545 describes a much larger effect on big heaps (about 0.1 s at 2 MB versus over 10 s at 32 GB). This machine cannot reproduce that, and these numbers do not test it.
  • The first batch of 2,000 requests takes about 2.4 to 2.7 s in every configuration, so for this app warmup is dominated by JIT and class loading, not heap growth.
  • Under ZGC, InitialHeapSize ergonomics are 98,566,144 bytes on JDK 25 but 8,388,608 bytes on JDK 27 and 28-ea (output/01-flag-probe.txt). I did not find which change causes that, so the post reports it as an observation only.
  • Timings drift between runs. Treat them as indicative, not as a result.

Licence

MIT, as the parent repository.