Files
javademos/docs/02-g1-default.md

3.4 KiB

2. G1 becomes the default, even on one CPU (JEP 523)

Prev: 1. What shipped · Next: 3. Compact object headers

The old rule

Since JDK 9 the JVM has chosen its collector by "server-class machine" ergonomics: G1 if it sees at least two CPUs and roughly 1792 MB of memory, Serial otherwise. A container limited to one CPU, or to 1 GB, quietly got Serial. JEP 523 removes the exception: G1 is chosen in every environment.

What the containers say

scripts/g1-default.sh runs GcReport in amazoncorretto:26 and :27 containers. Only the JDK version and the limits change.

Container JDK 26 picks JDK 27 picks Transcript
--cpus=1 --memory=2g Serial (UseSerialGC ... ERGONOMIC) G1 01
--cpus=2 --memory=2g G1 G1 01
--cpus=2 --memory=1g Serial G1 02

So both halves of the old rule are gone: CPU count and memory limit. An explicit -XX:+UseSerialGC still wins (03); its origin shows as VM_CREATION, not ERGONOMIC.

What it costs when your container is small

Workload allocates 50,000 short-lived objects per batch, keeps about 1% of them, and reports wall time, GC count and time, the slowest single batch and peak RSS. Three runs per configuration, 1 CPU, 2 GB (04):

4000 batches wall time GC count / total GC time slowest batch peak RSS
26, default (Serial) 6.0-6.4 s 1275 / ~1.85 s 115-142 ms 557 MB
27, default (G1) 8.2-8.4 s 140 / ~1.98 s 35-41 ms 547 MB
27, -XX:+UseSerialGC 5.0-5.7 s 1264 / ~1.66 s 119-128 ms 557 MB

The shape, not the digits: on one CPU, G1 has roughly 3x shorter worst-case stalls and takes about a third longer to finish the same allocation-heavy work. G1's concurrent work has to share the only CPU with your application.

A short-lived process makes it look worse (05, 400 batches): 26 finishes in ~0.53 s using ~102 MB RSS; 27 with G1 takes ~1.0 s and touches ~492 MB, because G1 grows the heap toward the 512 MB default maximum instead of collecting early. Serial on 27 matches 26 (~0.52 s, ~98 MB).

Two suspects, tested

scripts/g1-tuning.sh (06):

  1. JDK 27 also changed the heap free ratios G1 uses (MinHeapFreeRatio 40 -> 0, MaxHeapFreeRatio 70 -> 100). Restoring 40/70 changed nothing measurable.
  2. G1 being allowed to grow toward MaxHeapSize. Capping the heap at -Xmx256m cut peak RSS from ~492 MB to ~294 MB with about the same wall time.

Advice

  • Nothing to do if you already set a collector explicitly.
  • If you were relying on the implicit Serial in small containers and you are throughput- or footprint-bound, pin it: -XX:+UseSerialGC.
  • If you are happy with G1, set -Xmx (or -XX:MaxRAMPercentage) so the heap does not sprawl to the default maximum.
  • Note -XX:InitiatingHeapOccupancyPercent is deprecated in 27 in favour of -XX:G1IHOP (60).

Prev: 1. What shipped · Next: 3. Compact object headers