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:
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# The smallest container that can hold the catalog, before and after. For each memory limit the app is started
|
||||
# inside a cgroup with that limit and asked to load N products; the table says what happened.
|
||||
# ok the load finished
|
||||
# java-OOM the JVM threw OutOfMemoryError: the heap (a fraction of the limit) was too small
|
||||
# killed(...) the kernel killed the process: total memory, not just heap, went over the limit
|
||||
# no-result-in-25s the JVM stayed alive but the load (about a second when healthy) did not finish in 25
|
||||
# seconds: the heap is so tight that the collector runs continuously and makes no progress
|
||||
# Each cell is RUNS runs ("3/3 ok" = all three finished); a cell near the boundary can be mixed.
|
||||
# usage: container-sizing.sh [N products] [runs per cell]
|
||||
source "$(dirname "$0")/lib.sh"
|
||||
N="${1:-2000000}"; RUNS="${2:-3}"
|
||||
TMP="$(mktemp -d)"; RETRIES=0
|
||||
MB=$((1024*1024))
|
||||
|
||||
sweep() { # title, jvm-flags-for-all, limits...
|
||||
local title="$1" common="$2"; shift 2
|
||||
echo "== $title"
|
||||
printf '%-8s %-8s %-30s %-30s %-30s\n' "limit" "heap" "JDK 26 default" "JDK 27 default" "JDK 27 opt-out"
|
||||
for lim in "$@"; do
|
||||
local cells=() heap="?"
|
||||
for cfg in "26|$JDK26|" "27|$JDK27|" "27o|$JDK27|-XX:-UseCompactObjectHeaders"; do
|
||||
IFS='|' read -r tag jh fl <<<"$cfg"
|
||||
local ok=0 fails=() rss=()
|
||||
for r in $(seq 1 "$RUNS"); do
|
||||
d="$TMP/$tag-$lim-$r"
|
||||
CG_MEM=$((lim*MB)) CG_CPUS=2 run_app "$jh" "$N" "$d" $common $fl >/dev/null 2>&1
|
||||
h=$(kv "$d/memory-idle.txt" maxHeapMB); [ -n "$h" ] && heap="$h"
|
||||
[ -f "$d/retries" ] && RETRIES=$((RETRIES+1))
|
||||
out=$(cat "$d/outcome.txt")
|
||||
if [ "$out" = ok ]; then ok=$((ok+1)); rss+=("$(kv "$d/memory.txt" rssMB)"); else fails+=("${out%%(*}"); fi
|
||||
done
|
||||
cell="$ok/$RUNS ok"
|
||||
if [ $ok -gt 0 ]; then cell="$cell rss $(printf '%s\n' "${rss[@]}" | median)MB"; fi
|
||||
if [ ${#fails[@]} -gt 0 ]; then cell="$cell [$(printf '%s\n' "${fails[@]}" | sort | uniq -c | awk '{printf "%s%sx %s",sep,$1,$2; sep=" "}')]"; fi
|
||||
cells+=("$cell")
|
||||
done
|
||||
printf '%-8s %-8s %-30s %-30s %-30s\n' "${lim}MB" "${heap}MB" "${cells[0]}" "${cells[1]}" "${cells[2]}"
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
# ONLY=75 or ONLY=25 runs one of the two sweeps (each takes about 12 minutes); default is both.
|
||||
ONLY="${ONLY:-both}"
|
||||
echo "# $N products; 2 CPUs; $RUNS runs per cell; rss is the median of the runs that finished"
|
||||
if [ "$ONLY" != 25 ]; then
|
||||
sweep "Heap set to 75% of the container (-XX:MaxRAMPercentage=75)" "-XX:MaxRAMPercentage=75" 400 416 432 448 512 704
|
||||
fi
|
||||
if [ "$ONLY" != 75 ]; then
|
||||
sweep "Heap left at the JVM default (25% of the container)" "" 1024 1152 1216 1280 1536 2048
|
||||
fi
|
||||
echo "# runs that needed a startup retry (the JVM never came up, for a reason other than OOM or a kernel kill): $RETRIES"
|
||||
rm -rf "$TMP"
|
||||
Reference in New Issue
Block a user