diff --git a/README.md b/README.md
index 09a6897..441c513 100644
--- a/README.md
+++ b/README.md
@@ -73,6 +73,7 @@ the part most "ZGC is faster" posts leave out.
| [`jmh/`](jmh/src/main/java/com/ankurm/zgc/jmh) | Throughput and barrier microbenchmarks | JMH 1.37 |
| [`jdk27-memory/`](jdk27-memory) | Spring Boot 4.1 service measured on JDK 25, 26 and 27: compact object headers (JEP 534) and G1 everywhere (JEP 523), heap footprint, container sizing with real cgroup limits. Its README and `output/` replace a `docs/` folder; the write-up is [the post](https://ankurm.com/jdk-27-compact-object-headers-g1-default-memory-spring-boot/) | Spring Boot 4.1.1, three JDKs |
| [`flags/`](flags) | The flag-by-flag production cheat sheet: `MaxRAMPercentage` vs a hardcoded `-Xmx` (one fails safely, one gets the container SIGKILLed), `-XX:-UseContainerSupport`, the `ActiveProcessorCount` lie, and which diagnostic flags (`HeapDumpOnOutOfMemoryError`, `NativeMemoryTracking`) are worth leaving on in prod — on real Docker containers, JDK 25 and JDK 27. Its README and `docs/output/` replace a `docs/` folder; the write-up is [the post](https://ankurm.com/jvm-flags-for-spring-boot-in-containers-jdk-25-27/) | Spring Boot 4.1.1, Docker, two JDKs |
+| [`jdk28-zgc/`](jdk28-zgc) | ZGC startup and warmup versus initial heap size on JDK 25, 27 and 28 early access with a Spring Boot 4.1.1 server, plus a probe showing that JEP 545/546's `-XX:+ZAdaptiveHeapSizing` is not in any build yet. Its README and `output/` replace a `docs/` folder; the write-up is [the post](https://ankurm.com/zgc-jdk-28-adaptive-heap-sizing-faster-startup/) | Spring Boot 4.1.1, three JDKs |
### JMH benchmarks
diff --git a/jdk28-zgc/README.md b/jdk28-zgc/README.md
new file mode 100644
index 0000000..293a658
--- /dev/null
+++ b/jdk28-zgc/README.md
@@ -0,0 +1,78 @@
+# 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/`](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`](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
+
+```console
+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`](src/main/java/com/ankurm/zgc/DemoApplication.java) | One server: `/hello` allocates 16 KB, `/heap` reports committed and max heap |
+| [`scripts/startup.sh`](scripts/startup.sh) | Wall-clock ms from process start to first HTTP 200, repeated, with min/median/max |
+| [`scripts/warmup.sh`](scripts/warmup.sh) + [`scripts/Warmup.java`](scripts/Warmup.java) | 20,000 requests, 4 threads, timing each batch of 2,000; client is always JDK 25 |
+| [`scripts/run-all.sh`](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`](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`](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`](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.
diff --git a/jdk28-zgc/output/01-flag-probe.txt b/jdk28-zgc/output/01-flag-probe.txt
new file mode 100644
index 0000000..e63704d
--- /dev/null
+++ b/jdk28-zgc/output/01-flag-probe.txt
@@ -0,0 +1,30 @@
+== JDK 25
+openjdk version "25.0.4.1" 2026-08-18 LTS
+ size_t InitialHeapSize = 98566144 {product} {ergonomic}
+ size_t MaxHeapSize = 1568669696 {product} {ergonomic}
+ size_t SoftMaxHeapSize = 1411802726 {manageable} {ergonomic}
+ bool ZUncommit = true {product} {default}
+ uintx ZUncommitDelay = 300 {product} {default}
+-- probing -XX:+ZAdaptiveHeapSizing
+Unrecognized VM option 'ZAdaptiveHeapSizing'
+
+== JDK 27
+openjdk version "27" 2026-09-15
+ size_t InitialHeapSize = 8388608 {product} {ergonomic}
+ size_t MaxHeapSize = 1568669696 {product} {ergonomic}
+ size_t SoftMaxHeapSize = 1411802726 {manageable} {ergonomic}
+ bool ZUncommit = true {product} {default}
+ uintx ZUncommitDelay = 300 {product} {default}
+-- probing -XX:+ZAdaptiveHeapSizing
+Unrecognized VM option 'ZAdaptiveHeapSizing'
+
+== JDK 28-ea
+openjdk version "28-ea" 2027-03-23
+ size_t InitialHeapSize = 8388608 {product} {ergonomic}
+ size_t MaxHeapSize = 1568669696 {product} {ergonomic}
+ size_t SoftMaxHeapSize = 1411802726 {manageable} {ergonomic}
+ bool ZUncommit = true {product} {default}
+ uintx ZUncommitDelay = 300 {product} {default}
+-- probing -XX:+ZAdaptiveHeapSizing
+Unrecognized VM option 'ZAdaptiveHeapSizing'
+
diff --git a/jdk28-zgc/output/02-startup-vs-xms.txt b/jdk28-zgc/output/02-startup-vs-xms.txt
new file mode 100644
index 0000000..0a5494c
--- /dev/null
+++ b/jdk28-zgc/output/02-startup-vs-xms.txt
@@ -0,0 +1,90 @@
+jdk25 zgc default run 1: first-response 3439 ms, committed heap 156 MiB
+jdk25 zgc default run 2: first-response 3596 ms, committed heap 154 MiB
+jdk25 zgc default run 3: first-response 3325 ms, committed heap 154 MiB
+jdk25 zgc default run 4: first-response 3529 ms, committed heap 154 MiB
+jdk25 zgc default run 5: first-response 3251 ms, committed heap 154 MiB
+jdk25 zgc default SUMMARY: min 3251 ms, median 3439 ms, max 3596 ms (n=5)
+jdk25 zgc Xms64m run 1: first-response 3291 ms, committed heap 158 MiB
+jdk25 zgc Xms64m run 2: first-response 3233 ms, committed heap 154 MiB
+jdk25 zgc Xms64m run 3: first-response 3299 ms, committed heap 154 MiB
+jdk25 zgc Xms64m run 4: first-response 3488 ms, committed heap 156 MiB
+jdk25 zgc Xms64m run 5: first-response 3396 ms, committed heap 156 MiB
+jdk25 zgc Xms64m SUMMARY: min 3233 ms, median 3299 ms, max 3488 ms (n=5)
+jdk25 zgc Xms1g run 1: first-response 3502 ms, committed heap 1024 MiB
+jdk25 zgc Xms1g run 2: first-response 3475 ms, committed heap 1024 MiB
+jdk25 zgc Xms1g run 3: first-response 3478 ms, committed heap 1024 MiB
+jdk25 zgc Xms1g run 4: first-response 3728 ms, committed heap 1024 MiB
+jdk25 zgc Xms1g run 5: first-response 3395 ms, committed heap 1024 MiB
+jdk25 zgc Xms1g SUMMARY: min 3395 ms, median 3478 ms, max 3728 ms (n=5)
+jdk25 zgc Xms3g run 1: first-response 3836 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g run 2: first-response 4070 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g run 3: first-response 3886 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g run 4: first-response 3717 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g run 5: first-response 3827 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g SUMMARY: min 3717 ms, median 3836 ms, max 4070 ms (n=5)
+jdk25 zgc Xms3g pretouch run 1: first-response 5058 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g pretouch run 2: first-response 4941 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g pretouch run 3: first-response 4801 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g pretouch run 4: first-response 4834 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g pretouch run 5: first-response 4626 ms, committed heap 3072 MiB
+jdk25 zgc Xms3g pretouch SUMMARY: min 4626 ms, median 4834 ms, max 5058 ms (n=5)
+jdk27 zgc default run 1: first-response 3598 ms, committed heap 148 MiB
+jdk27 zgc default run 2: first-response 3421 ms, committed heap 148 MiB
+jdk27 zgc default run 3: first-response 3510 ms, committed heap 148 MiB
+jdk27 zgc default run 4: first-response 3280 ms, committed heap 152 MiB
+jdk27 zgc default run 5: first-response 3239 ms, committed heap 150 MiB
+jdk27 zgc default SUMMARY: min 3239 ms, median 3421 ms, max 3598 ms (n=5)
+jdk27 zgc Xms64m run 1: first-response 3276 ms, committed heap 152 MiB
+jdk27 zgc Xms64m run 2: first-response 3252 ms, committed heap 146 MiB
+jdk27 zgc Xms64m run 3: first-response 3348 ms, committed heap 150 MiB
+jdk27 zgc Xms64m run 4: first-response 3479 ms, committed heap 146 MiB
+jdk27 zgc Xms64m run 5: first-response 3156 ms, committed heap 152 MiB
+jdk27 zgc Xms64m SUMMARY: min 3156 ms, median 3276 ms, max 3479 ms (n=5)
+jdk27 zgc Xms1g run 1: first-response 3165 ms, committed heap 1024 MiB
+jdk27 zgc Xms1g run 2: first-response 3475 ms, committed heap 1024 MiB
+jdk27 zgc Xms1g run 3: first-response 3412 ms, committed heap 1024 MiB
+jdk27 zgc Xms1g run 4: first-response 3275 ms, committed heap 1024 MiB
+jdk27 zgc Xms1g run 5: first-response 3237 ms, committed heap 1024 MiB
+jdk27 zgc Xms1g SUMMARY: min 3165 ms, median 3275 ms, max 3475 ms (n=5)
+jdk27 zgc Xms3g run 1: first-response 4142 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g run 2: first-response 3846 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g run 3: first-response 3618 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g run 4: first-response 3563 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g run 5: first-response 3593 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g SUMMARY: min 3563 ms, median 3618 ms, max 4142 ms (n=5)
+jdk27 zgc Xms3g pretouch run 1: first-response 4782 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g pretouch run 2: first-response 4560 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g pretouch run 3: first-response 4385 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g pretouch run 4: first-response 4532 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g pretouch run 5: first-response 4623 ms, committed heap 3072 MiB
+jdk27 zgc Xms3g pretouch SUMMARY: min 4385 ms, median 4560 ms, max 4782 ms (n=5)
+jdk28ea zgc default run 1: first-response 3439 ms, committed heap 144 MiB
+jdk28ea zgc default run 2: first-response 3918 ms, committed heap 144 MiB
+jdk28ea zgc default run 3: first-response 3290 ms, committed heap 144 MiB
+jdk28ea zgc default run 4: first-response 3420 ms, committed heap 146 MiB
+jdk28ea zgc default run 5: first-response 3170 ms, committed heap 146 MiB
+jdk28ea zgc default SUMMARY: min 3170 ms, median 3420 ms, max 3918 ms (n=5)
+jdk28ea zgc Xms64m run 1: first-response 3350 ms, committed heap 146 MiB
+jdk28ea zgc Xms64m run 2: first-response 3217 ms, committed heap 148 MiB
+jdk28ea zgc Xms64m run 3: first-response 3367 ms, committed heap 148 MiB
+jdk28ea zgc Xms64m run 4: first-response 3274 ms, committed heap 150 MiB
+jdk28ea zgc Xms64m run 5: first-response 3522 ms, committed heap 150 MiB
+jdk28ea zgc Xms64m SUMMARY: min 3217 ms, median 3350 ms, max 3522 ms (n=5)
+jdk28ea zgc Xms1g run 1: first-response 3458 ms, committed heap 1024 MiB
+jdk28ea zgc Xms1g run 2: first-response 3733 ms, committed heap 1024 MiB
+jdk28ea zgc Xms1g run 3: first-response 3478 ms, committed heap 1024 MiB
+jdk28ea zgc Xms1g run 4: first-response 3642 ms, committed heap 1024 MiB
+jdk28ea zgc Xms1g run 5: first-response 4136 ms, committed heap 1024 MiB
+jdk28ea zgc Xms1g SUMMARY: min 3458 ms, median 3642 ms, max 4136 ms (n=5)
+jdk28ea zgc Xms3g run 1: first-response 3590 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g run 2: first-response 3871 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g run 3: first-response 3803 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g run 4: first-response 3691 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g run 5: first-response 3857 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g SUMMARY: min 3590 ms, median 3803 ms, max 3871 ms (n=5)
+jdk28ea zgc Xms3g pretouch run 1: first-response 5010 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g pretouch run 2: first-response 4882 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g pretouch run 3: first-response 5040 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g pretouch run 4: first-response 5283 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g pretouch run 5: first-response 4764 ms, committed heap 3072 MiB
+jdk28ea zgc Xms3g pretouch SUMMARY: min 4764 ms, median 5010 ms, max 5283 ms (n=5)
diff --git a/jdk28-zgc/output/03-warmup.txt b/jdk28-zgc/output/03-warmup.txt
new file mode 100644
index 0000000..2c69430
--- /dev/null
+++ b/jdk28-zgc/output/03-warmup.txt
@@ -0,0 +1,24 @@
+== jdk25 zgc default
+batch ms: 2678 1147 993 749 829 667 715 591 745 588
+total ms: 9708
+committed after load: 342 MiB (max 1496 MiB)
+== jdk25 zgc Xms3g
+batch ms: 2606 1155 909 958 748 674 546 409 637 548
+total ms: 9193
+committed after load: 3072 MiB (max 3072 MiB)
+== jdk25 zgc Xms64m
+batch ms: 2442 1221 971 810 997 689 648 548 480 437
+total ms: 9247
+committed after load: 312 MiB (max 1496 MiB)
+== jdk28ea zgc default
+batch ms: 2567 1217 977 979 907 826 730 590 602 512
+total ms: 9912
+committed after load: 284 MiB (max 1496 MiB)
+== jdk28ea zgc Xms3g
+batch ms: 2431 1282 1112 947 716 709 651 631 566 559
+total ms: 9608
+committed after load: 3072 MiB (max 3072 MiB)
+== jdk28ea zgc Xms64m
+batch ms: 2590 1182 1076 886 796 704 779 717 561 598
+total ms: 9893
+committed after load: 414 MiB (max 1496 MiB)
diff --git a/jdk28-zgc/pom.xml b/jdk28-zgc/pom.xml
new file mode 100644
index 0000000..a84ea0e
--- /dev/null
+++ b/jdk28-zgc/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 4.1.1
+
+
+ com.ankurm
+ jdk28-zgc
+ 1.0.0
+ jdk28-zgc
+ Startup and heap-sizing harness for ZGC across JDK 25, 27 and 28 early access
+
+ 25
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webmvc
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/jdk28-zgc/scripts/Warmup.java b/jdk28-zgc/scripts/Warmup.java
new file mode 100644
index 0000000..d2ba4d8
--- /dev/null
+++ b/jdk28-zgc/scripts/Warmup.java
@@ -0,0 +1,37 @@
+import java.net.URI;
+import java.net.http.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+/** Fires TOTAL requests with THREADS threads and reports how long each batch of BATCH took. */
+public class Warmup {
+ public static void main(String[] a) throws Exception {
+ int port = Integer.parseInt(a[0]);
+ int total = 20_000, batch = 2_000, threads = 4;
+ HttpClient c = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
+ HttpRequest rq = HttpRequest.newBuilder(URI.create("http://localhost:" + port + "/hello")).build();
+ AtomicInteger done = new AtomicInteger();
+ long[] batchEnd = new long[total / batch];
+ long t0 = System.nanoTime();
+ ExecutorService ex = Executors.newFixedThreadPool(threads);
+ List> fs = new ArrayList<>();
+ for (int t = 0; t < threads; t++) fs.add(ex.submit(() -> {
+ try {
+ while (true) {
+ int n = done.incrementAndGet();
+ if (n > total) return null;
+ c.send(rq, HttpResponse.BodyHandlers.discarding());
+ if (n % batch == 0) batchEnd[n / batch - 1] = System.nanoTime();
+ }
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }));
+ for (Future> f : fs) f.get();
+ ex.shutdown();
+ StringBuilder sb = new StringBuilder("batch ms:");
+ long prev = t0;
+ for (long e : batchEnd) { sb.append(' ').append((e - prev) / 1_000_000); prev = e; }
+ System.out.println(sb);
+ System.out.println("total ms: " + (prev - t0) / 1_000_000);
+ }
+}
diff --git a/jdk28-zgc/scripts/run-all.sh b/jdk28-zgc/scripts/run-all.sh
new file mode 100755
index 0000000..f1e40d7
--- /dev/null
+++ b/jdk28-zgc/scripts/run-all.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+# Regenerates every file in output/. Set J25, J27, J28 to the three JDK home directories.
+# Timing results drift between runs and machines; treat them as indicative, not exact.
+set -u
+HERE="$(cd "$(dirname "$0")" && pwd)"
+OUT="$HERE/../output"; mkdir -p "$OUT"
+: "${J25:?}" "${J27:?}" "${J28:?}"
+export JDK_CLIENT="$J25"
+RUNS=${RUNS:-5}
+
+# 01 - what does each JDK say about the ZGC flags the two JEPs talk about?
+{
+ for p in "25|$J25" "27|$J27" "28-ea|$J28"; do
+ v=${p%%|*}; h=${p#*|}
+ echo "== JDK $v"
+ "$h/bin/java" -version 2>&1 | grep -v Picked | sed -n 1p
+ "$h/bin/java" -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+PrintFlagsFinal -version 2>&1 \
+ | grep -E ' (InitialHeapSize|MaxHeapSize|SoftMaxHeapSize|ZUncommit|ZUncommitDelay) ' | sed 's/ \{2,\}/ /g'
+ echo "-- probing -XX:+ZAdaptiveHeapSizing"
+ "$h/bin/java" -XX:+UseZGC -XX:+ZAdaptiveHeapSizing -version 2>&1 | grep -v Picked | sed -n 1p
+ echo
+ done
+} > "$OUT/01-flag-probe.txt"
+
+# 02 - startup versus initial heap size
+{
+ for p in "jdk25|$J25" "jdk27|$J27" "jdk28ea|$J28"; do
+ l=${p%%|*}; h=${p#*|}
+ "$HERE/startup.sh" "$h" "$l zgc default" "$RUNS" -XX:+UseZGC
+ "$HERE/startup.sh" "$h" "$l zgc Xms64m" "$RUNS" -XX:+UseZGC -Xms64m
+ "$HERE/startup.sh" "$h" "$l zgc Xms1g" "$RUNS" -XX:+UseZGC -Xms1g
+ "$HERE/startup.sh" "$h" "$l zgc Xms3g" "$RUNS" -XX:+UseZGC -Xms3g
+ "$HERE/startup.sh" "$h" "$l zgc Xms3g pretouch" "$RUNS" -XX:+UseZGC -Xms3g -XX:+AlwaysPreTouch
+ done
+} > "$OUT/02-startup-vs-xms.txt" 2>&1
+
+# 03 - warmup: how long do the first 20,000 requests take?
+{
+ for p in "jdk25|$J25" "jdk28ea|$J28"; do
+ l=${p%%|*}; h=${p#*|}
+ "$HERE/warmup.sh" "$h" "$l zgc default" -XX:+UseZGC
+ "$HERE/warmup.sh" "$h" "$l zgc Xms3g" -XX:+UseZGC -Xms3g
+ "$HERE/warmup.sh" "$h" "$l zgc Xms64m" -XX:+UseZGC -Xms64m
+ done
+} > "$OUT/03-warmup.txt" 2>&1
diff --git a/jdk28-zgc/scripts/startup.sh b/jdk28-zgc/scripts/startup.sh
new file mode 100755
index 0000000..60ce355
--- /dev/null
+++ b/jdk28-zgc/scripts/startup.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+# Usage: startup.sh