Java Performance — 17 vs 25 vs 28 EA (Valhalla)

Generated 2026-08-14 11:47 UTC · JMH 1.37 · identical code, only the JDK changes

⚡ Speed — Java 17 → Java 25

Lower ms/op is better.

BenchmarkJava 17Java 25ΔUnitVerdict
allocateAndProcessStrings (count=1000000) 8.18 5.97 +27.0% ms/op faster/leaner
allocateAndProcessStrings (count=5000000) 40.89 29.86 +27.0% ms/op faster/leaner
sumPrimitiveArray (size=1000000) 0.76 0.39 +48.3% ms/op faster/leaner
virtualThreads (taskCount=10000) 6,347.66 7.97 +99.9% ms/op faster/leaner

🧠 Memory — Java 17 → Java 25

Bytes allocated per operation (GC profiler). Lower is better.

BenchmarkJava 17Java 25ΔUnitVerdict
platformThreadPool (taskCount=10000) 1.3 MB 998.2 KB +24.3% B/op faster/leaner
streamFilterMapReduce (size=1000000) 433.92 361.95 +16.6% B/op faster/leaner

🔮 Valhalla — real value records (preview)

Same benchmark, record Point(...)value record Point(...). One keyword changed.

BenchmarkJava 25 (record)Java 28 EA (value record)ΔUnitVerdict
computeDistances (size=1000000) 22.10 5.52 +75.0% ms/op faster/leaner
sumPointsRecord (size=1000000) 19.12 1.84 +90.4% ms/op faster/leaner

🧠 Valhalla memory — record vs value record

Bytes allocated per operation (GC profiler), record Point(...)value record Point(...). Lower is better.

This is where Valhalla's actual promise lives: a flattened value record array should need no per-element object header at all. Whether that shows up here depends on whether array-flattening is engaging in this preview build for this run — it isn't hand-picked either way.

BenchmarkJava 25 (record)Java 28 EA (value record)ΔUnitVerdict
computeDistances (size=1000000) 20.0 MB 8.0 MB +60.0% B/op faster/leaner
sumPointsRecord (size=1000000) 20.0 MB 8.0 MB +60.0% B/op faster/leaner