Add jdk27-memory: compact object headers and G1-everywhere on a Spring Boot service

Spring Boot 4.1.1 catalog service measured on JDK 25, 26 and 27: live heap 320 MB to 273 MB with compact headers, per-class bytes per instance, container-sizing sweeps with real cgroup limits, 1-CPU Serial vs G1 with Native Memory Tracking, removed flags (MaxRAM, UseCompressedClassPointers), and a kernel OOM-kill check. Outputs in jdk27-memory/output.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
This commit is contained in:
Claude
2026-09-24 15:09:55 +00:00
parent e189da79ba
commit e83c9949d8
29 changed files with 1041 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# What each JDK decides by default, and what the flags do. Every line is the JVM's own answer
# (java -XX:+PrintFlagsFinal), not something inferred from documentation.
source "$(dirname "$0")/lib.sh"
show() { # label jdk flags... (set CG_MEM/CG_CPUS to run inside a container-style cgroup)
local label="$1" jh="$2"; shift 2
local out cg=""
if [ -n "${CG_MEM:-}" ]; then
cg="fl$$-$RANDOM"; cg_create "$cg" "$CG_MEM" "${CG_CPUS:-2}"
out=$(bash -c "$CG_JOIN" _ "$cg" "$jh/bin/java" "$@" -XX:+PrintFlagsFinal -version 2>&1)
cg_remove "$cg"
else
out=$("$jh/bin/java" "$@" -XX:+PrintFlagsFinal -version 2>&1)
fi
if ! echo "$out" | grep -q 'UseCompactObjectHeaders'; then
printf '%-52s -> JVM refused to start:\n' "$label"; echo "$out" | head -3 | sed 's/^/ /'; return
fi
local ch gc heap
ch=$(echo "$out" | awk '$2=="UseCompactObjectHeaders"{print $4}')
gc=$(echo "$out" | awk '($2=="UseG1GC"||$2=="UseSerialGC"||$2=="UseParallelGC"||$2=="UseZGC") && $4=="true"{print $2}' | tr '\n' ' ')
heap=$(echo "$out" | awk '$2=="MaxHeapSize"{printf "%d", $4/1048576}')
printf '%-52s -> compact=%-5s collector=%-13s MaxHeapSize=%sMB\n' "$label" "$ch" "$gc" "$heap"
echo "$out" | grep -E '^(OpenJDK 64-Bit Server VM warning|Error|Unrecognized)' | sed 's/^/ JVM says: /' | head -2
}
for v in 25 26 27; do
jh_var="JDK$v"; jh="${!jh_var}"
echo "== JDK $v: $("$jh/bin/java" -version 2>&1 | sed -n 2p)"
show "default (this machine: 2 CPUs)" "$jh"
show "-XX:+UseCompactObjectHeaders" "$jh" -XX:+UseCompactObjectHeaders
show "-XX:-UseCompactObjectHeaders" "$jh" -XX:-UseCompactObjectHeaders
echo
done
echo "== The same JDKs in a container: 1 GB memory limit, 1 CPU (a cgroup, set the way Docker sets it)"
for v in 25 26 27; do
jh_var="JDK$v"; jh="${!jh_var}"
CG_MEM=$((1024*1024*1024)) CG_CPUS=1 show "JDK $v, 1 GB, 1 CPU" "$jh"
CG_MEM=$((1024*1024*1024)) CG_CPUS=1 show "JDK $v, 1 GB, 1 CPU, MaxRAMPercentage=75" "$jh" -XX:MaxRAMPercentage=75
done
echo
echo "== 1 GB, 2 CPUs"
for v in 26 27; do
jh_var="JDK$v"; jh="${!jh_var}"
CG_MEM=$((1024*1024*1024)) CG_CPUS=2 show "JDK $v, 1 GB, 2 CPUs" "$jh"
done
echo
echo "== -XX:MaxRAM: the flag many people used to fake a container limit"
show "JDK 26 -XX:MaxRAM=1g" "$JDK26" -XX:MaxRAM=1g
show "JDK 27 -XX:MaxRAM=1g" "$JDK27" -XX:MaxRAM=1g
echo
echo "== Compact headers with each collector on JDK 27"
for gc in UseG1GC UseParallelGC UseSerialGC UseZGC; do
show "JDK 27 -XX:+$gc" "$JDK27" -XX:+$gc
done
echo
echo "== Compressed pointers on JDK 27"
show "JDK 27 -XX:-UseCompressedClassPointers" "$JDK27" -XX:-UseCompressedClassPointers
show "JDK 27 -XX:-UseCompressedOops" "$JDK27" -XX:-UseCompressedOops
show "JDK 27 -Xmx32g (a large explicit heap)" "$JDK27" -Xmx32g