Files
Claude e83c9949d8 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
2026-09-24 15:09:55 +00:00

57 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Heap footprint of the same jar on JDK 25, 26 and 27, with compact object headers on and off.
# usage: footprint.sh [N products] [runs per configuration]
source "$(dirname "$0")/lib.sh"
N="${1:-2000000}"; RUNS="${2:-3}"
TMP="$(mktemp -d)"
MEDS=(); ALL=()
row() { # label jdk flags...
local label="$1" jh="$2"; shift 2
local idle=() live=() rss=() gcn=() gcms=() ns=() start=()
for r in $(seq 1 "$RUNS"); do
run_app "$jh" "$N" "$TMP/$label-$r" -Xms1g -Xmx1g "$@" || { echo "$label run $r FAILED"; return; }
local d="$TMP/$label-$r"
idle+=("$(kv "$d/memory-idle.txt" heapLiveAfterGcMB)")
live+=("$(kv "$d/memory.txt" heapLiveAfterGcMB)")
rss+=("$(kv "$d/memory.txt" rssMB)")
gcn+=("$(kv "$d/load.txt" gcCountDuringLoad)")
gcms+=("$(kv "$d/load.txt" gcMillisDuringLoad)")
ns+=("$(kv "$d/lookups.txt" nsPerLookup)")
ALL+=("${gcn[-1]} ${rss[-1]} ${ns[-1]}")
printf 'run %s/%s idle=%sMB live=%sMB rss=%sMB gcDuringLoad=%s (%sms) lookup=%sns compact=%s\n' "$label" "$r" \
"${idle[-1]}" "${live[-1]}" "${rss[-1]}" "${gcn[-1]}" "${gcms[-1]}" "${ns[-1]}" "$(kv "$d/memory.txt" UseCompactObjectHeaders)"
done
MEDS+=("$(printf 'MED %-22s idle=%sMB live=%sMB rss=%sMB gcDuringLoad=%s gcMs=%s lookupNs=%s' "$label" \
"$(printf '%s\n' "${idle[@]}" | median)" "$(printf '%s\n' "${live[@]}" | median)" "$(printf '%s\n' "${rss[@]}" | median)" \
"$(printf '%s\n' "${gcn[@]}" | median)" "$(printf '%s\n' "${gcms[@]}" | median)" "$(printf '%s\n' "${ns[@]}" | median)")")
echo "${MEDS[-1]}"
}
echo "# $(date -u +%F) ${N} products, -Xms1g -Xmx1g, G1, ${RUNS} runs per configuration; MED lines are medians"
echo "# JDK25=$("$JDK25/bin/java" -version 2>&1 | sed -n 2p)"
echo "# JDK26=$("$JDK26/bin/java" -version 2>&1 | sed -n 2p)"
echo "# JDK27=$("$JDK27/bin/java" -version 2>&1 | sed -n 2p)"
row jdk25-default "$JDK25"
row jdk25-compact "$JDK25" -XX:+UseCompactObjectHeaders
row jdk26-default "$JDK26"
row jdk26-compact "$JDK26" -XX:+UseCompactObjectHeaders
row jdk27-default "$JDK27"
row jdk27-optout "$JDK27" -XX:-UseCompactObjectHeaders
echo
echo "== medians of $RUNS runs per configuration (idle = live set of the idle app; live = after loading the catalog)"
printf '%s\n' "${MEDS[@]}"
echo
stats() { sort -n | awk '{a[NR]=$1} END{printf "min %d / median %d / max %d", a[1], a[int((NR+1)/2)], a[NR]}'; }
echo "== the same runs, grouped by whether a collection ran while the catalog was loading (all configurations together)"
for g in zero some; do
if [ $g = zero ]; then sel='$1==0'; label="no collection during load"; else sel='$1>0'; label="a collection during load"; fi
n=$(printf '%s\n' "${ALL[@]}" | awk "$sel" | wc -l)
printf '%-27s runs=%-3s rss MB: %s lookup ns: %s\n' "$label" "$n" \
"$(printf '%s\n' "${ALL[@]}" | awk "$sel {print \$2}" | stats)" "$(printf '%s\n' "${ALL[@]}" | awk "$sel {print \$3}" | stats)"
done
# keep one histogram per JVM for the class-level table
mkdir -p "$MOD/target/hist"
for c in jdk26-default jdk27-default jdk27-optout; do cp "$TMP/$c-1/histogram.txt" "$MOD/target/hist/$c.txt"; done
rm -rf "$TMP"