Java 27 Released with G1 as the Default Garbage Collector Everywhere

Java 27 Released with G1 as the Default Garbage Collector Everywhere

Java 27 is out, and the change with the widest reach is that G1 is now the default garbage collector everywhere, including the small-heap and single-core configurations that previously defaulted to SerialGC.

Why the default mattered

The JVM has historically picked a collector based on what it found at startup: available cores, heap size, and whether the machine looked like a server. Below certain thresholds it chose SerialGC, which stops every application thread for the entire collection.

That heuristic was written for physical machines and aged badly in containers. A container limited to one CPU and 512MB of memory looks like a small embedded system to the JVM, so a modest web service in Kubernetes could silently get the stop-the-world collector and multi-hundred-millisecond pauses nobody asked for.

G1 is concurrent and generational, doing most of its work alongside the application and aiming for predictable pause targets rather than minimal footprint.

The tradeoff G1 makes is real: slightly higher memory overhead and slightly lower peak throughput in exchange for far better pause behaviour. For essentially every containerised service, that is the right trade, and it is now what you get without configuring anything.

If you were relying on the old default, check your memory headroom before upgrading. If you had already set -XX:+UseG1GC explicitly, nothing changes.

Compact Object Headers

Every Java object carries a header holding identity hash, locking state, and a class pointer. Compact Object Headers shrinks it.

On a heap with tens of millions of small objects, which is normal for a JVM service, a few bytes per object compounds into a meaningful percentage of total heap. Less memory per object means more objects in cache, fewer collections, and better locality.

This is the sort of change with no API surface and no code to write, which delivers a few percent across everything.

TLS

Continued improvements, which for a runtime that spends most of its life talking to other services over HTTPS is unglamorous and load-bearing.

Upgrading

sudo apt install openjdk-27-jdk
sudo dnf install java-27-openjdk

java -version

Java’s compatibility record is genuinely strong and the usual breakages come from elsewhere: bytecode manipulation libraries, agents, and anything reflecting into JDK internals, all of which tend to need their own updates before a major version works.

The other question is whether this is an LTS release. Java’s cadence gives six-month feature releases with LTS designations on a longer interval, and production deployments generally track the LTS rather than every release. Check which one 27 is before planning a migration around it.

On the Linux side, our static and dynamic linking guide is relevant background for anyone building native images, and our OOM killer explainer covers what happens when a JVM heap and a container memory limit disagree, which remains one of the more common production surprises.

Background reading

Explainers for the concepts behind this story.