Java 27 Deep Dive: How Default Changes Are Quietly Reshaping Production Environments

Java 27's 9 JEPs quietly enable compact object headers, universal G1 GC, credential redaction, and post-quantum TLS by default.
Java 27 is the smallest release in recent years, yet it delivers meaningful changes to default behavior. Compact object headers (8 bytes) are now on by default, reducing heap usage by ~22%. G1 becomes the unconditional default GC, eliminating surprise Serial GC usage in small containers. Flight Recorder now redacts passwords and tokens before writing to disk. TLS 1.3 gains built-in hybrid post-quantum key exchange (X25519 + ML-KEM) to defend against harvest-now-decrypt-later attacks. Nearly all changes require zero user action, and they'll all be enforced in the next LTS, Java 29. The bigger story comes with Java 28, when Project Valhalla's value classes finally arrive as a preview feature.
Java 27 is officially released, and it's the smallest update in recent years — just 9 JEPs (compared to 24 in Java 24, 18 in Java 25, and 10 in Java 26). But don't let the numbers fool you. This "smaller" release has quietly changed a number of default configurations under the hood. Even if you don't write a single line of new code, just upgrading — or migrating to the next LTS, Java 29 — will change how things behave in production.
This article is based on an in-depth walkthrough of Java 27 by a Java developer on YouTube, summarizing the changes that truly deserve your attention.
Compact Object Headers: Enabled by Default, Shrinking Heap Memory
The object header is the metadata the JVM attaches to every heap object — used for locking, garbage collection, and identifying the object's class. This header has long been 12 bytes. Compact object headers compress it down to 8 bytes, saving 4 bytes per object.
Sounds trivial? But a heap never has just one object — it has hundreds of millions of tiny ones: every Optional, every DTO, every order line item, every bloated List. They all get 4 bytes slimmer.

This feature actually debuted in Java 25, but required manually enabling the UseCompactObjectHeaders flag. In practice, most people don't change JVM flags while a service is running fine — "if it ain't broke, don't fix it." In Java 27, the flag is no longer necessary. Compact object headers are now the default.
The benchmark numbers in the JEP are compelling: on the SPECjbb2015 benchmark, heap usage dropped 22%, CPU time fell 8%, and garbage collection frequency decreased 15%. Sure, that's a single benchmark — upgrading won't actually cut your AWS bill by 22%. But it's worth noting that Amazon has already enabled this feature across hundreds of production services (mostly via backports to Java 17 and 21), and SAP enabled it as the default in their JDK even before Oracle did.
If something does go wrong, you can disable it temporarily with -UseCompactObjectHeaders — but keep in mind that's a temporary measure. Per JEP 450, the old 12-byte object header is ultimately slated for complete removal from the JDK.
Garbage Collector: G1 Becomes the Unconditional Default
Many people don't realize that while G1 has been the "default" garbage collector since Java 9, that default has always been conditional. If you didn't explicitly specify a collector, the JVM would check your machine: if it found only 1 CPU or less than 1792 MB of memory, it would give you the Serial collector.
This means a small container, a Lambda, or a single-core Pod has quietly been running Serial all along. The same application could end up using different collectors depending on what size machine it landed on.
Java 27 fixes this: when no collector is specified, G1 is used unconditionally, regardless of machine size.
This isn't completely free. Oracle notes that on small machines, G1 has comparable memory overhead to Serial but slightly lower raw throughput — in exchange for better maximum latency, meaning improved tail latency at the cost of marginally lower peak throughput. For most services, that's exactly the trade-off you'd want to make. If not, Serial hasn't disappeared — just set UseSerialGC to keep using it.
G1 (Garbage-First) replaced Parallel GC as the default in Java 9. Its core design divides the heap into equal-sized "Regions" and prioritizes collecting the ones with the fewest surviving objects (i.e., the most garbage), maximizing reclamation efficiency within predictable pause times. Serial GC, by contrast, performs all collection work on a single thread with no concurrency overhead — in extremely small heaps and single-core environments, this actually avoids the extra cost of multi-thread coordination, which is why the JVM historically treated it as the "pragmatic choice" for resource-constrained scenarios. But with containerization now ubiquitous, a "single-core Pod" no longer implies an underpowered old machine — it could be a modern cloud instance with ample memory and excellent I/O. In that context, Serial GC's tail latency characteristics become a liability. Java 27's correction reflects this reality: machine specs are no longer a reliable signal for inferring the optimal collection strategy, and standardizing on G1 delivers more consistent, predictable behavior.
Flight Recorder: Sensitive Data Redacted by Default
Flight Recorder captures everything happening in a running JVM, so that when something goes wrong at 2 AM in production, you can reconstruct exactly what happened. The problem is that "everything" includes how the process was started.

The JEP provides concrete examples: access tokens in environment variables, keystore passwords in system properties, database passwords in command-line arguments — three secrets. Before Java 27, all three would appear in plaintext in the recording file. When someone copy-pastes that dump into a Jira ticket, or hands it off to an AI agent, your production credentials end up somewhere they shouldn't be.
Java 27 redacts this content before it's written to disk, and this works by default — no configuration required.
Post-Quantum Cryptography: Defending Against "Harvest Now, Decrypt Later"
This is the most interesting change in this release — JEP 527, related to quantum computing. It's not about making your application better today; it's about whether the traffic you're encrypting today will still be secure 10 to 15 years from now.

Java 27 builds post-quantum key exchange directly into TLS 1.3 and the JDK itself. Today's quantum computers can't break these encryptions — but this JEP defends against an attack that's already happening: "harvest now, decrypt later." Attackers intercept your encrypted traffic today, can't read it yet, but store it for ten or fifteen years until quantum computers are mature enough to crack it.
For anyone handling medical records, bank transfers, government data, or any information that will still matter a decade from now, you need encryption that can withstand the computers that will exist then.
On the implementation side, the JEP adds hybrid key exchange to TLS 1.3: it runs both the classical elliptic curve key exchange X25519 and the post-quantum algorithm ML-KEM simultaneously, combining the shared secrets from both into one. It's designed as a hybrid because if ML-KEM has a flaw (post-quantum algorithms have had issues before), the classical side still provides a safety net — and if quantum computers do materialize, the ML-KEM side remains reliable. It's fundamentally redundancy: an attacker must break both simultaneously.
Per Oracle's guidance, if your application uses Java's standard javax.net.ssl stack and hasn't overridden the TLS named groups, this feature is active by default with no code changes required.
ML-KEM (Module Lattice-based Key Encapsulation Mechanism) is a post-quantum key encapsulation algorithm formally standardized by NIST in 2024, previously known as CRYSTALS-Kyber. Its security is based on the Module Learning With Errors (Module-LWE) problem — no known quantum algorithm can solve it in polynomial time, whereas classical RSA and elliptic curve cryptography (ECC) would be efficiently broken by Shor's algorithm on a sufficiently powerful quantum computer. X25519 is a Diffie-Hellman key exchange protocol based on Curve25519, known for high performance and resistance to side-channel attacks — it's the most widely used key exchange algorithm in TLS 1.3 today. Combining the two is known in post-quantum cryptography as "hybrid key exchange," and its logic is simple: security is taken from the stronger of the two — as long as one algorithm remains unbroken, the entire key exchange is secure. This design is especially valuable during the transition period before NIST finalized its standards, since new algorithms' implementations and mathematical foundations may still harbor undiscovered flaws.
Features Still in Preview or Incubation
Five JEPs remain in preview or incubation status:
- Lazy Constants: Third preview
- Primitive Types in Patterns: Fifth preview — doing a
switchonintwithout boxing - PEM Encoding: Third preview
- Structured Concurrency: Seventh preview, continuously previewing since Java 21
- Vector API: 12th incubation, going back to Java 16
The Vector API's delay in finalizing has a clear reason: the JEP explicitly states it's waiting on Valhalla. The team doesn't want to finalize an API against one object model, only to have value classes change everything underneath it.
Project Valhalla is a long-running JDK research project Oracle launched in 2014. Its core goal is to introduce "value types" (value classes) — inline data carriers without object identity that can be allocated on the stack or laid out flat in arrays, just like int, completely eliminating the "boxing tax" that current generics and collections impose on primitive types. The Vector API depends on Valhalla because high-performance vector operations require packing large numbers of values into contiguous memory, and the heap reference semantics and object header overhead of the current object model break that layout. Once value classes land, the JDK can map types like VectorFloat256 directly to the CPU's SIMD registers without indirect access through references. Structured Concurrency has also stayed in preview across multiple versions — primarily because the community is still debating API details (such as scope inheritance and exception propagation strategies) rather than questioning the technical implementation. This actually demonstrates the preview mechanism working exactly as designed: giving sufficient time to gather real-world usage feedback before finalizing.
Everything On by Default — The Focus Is the Next LTS
Java 27 has one consistent theme: you barely have to do anything. Migrate to Java 27 and all of the above features are on by default. Even if you don't migrate — as most people realistically won't — they'll all be enabled by default in the next LTS, Java 29, releasing a year from now.
But the real excitement is actually Java 28, shipping in March. That's when Valhalla's value classes will formally integrate into JDK 28 as a preview feature — something Java has been promising for over a decade. That'll be worth a separate deep dive.
One observation worth sitting with: people often say Java is behind the times — yet here it is, preparing for quantum threats decades away. That's worth giving Java credit for.
Related articles

Claude Code v2.1.276 Released: Fixes Proxy/Gateway 400 Error Regression
Claude Code v2.1.276 fixes a critical regression from v2.1.275 where all requests via proxy or gateway failed with a 400 error (Input tag 'advisor_20260301'). Upgrade now.

Andrew Ng on Agentic AI: Cutting Through the Hype to Find Real Value in Agent Development
Andrew Ng's Agentic AI course intro: separating hype from real value, exploring agent workflows in customer service, research, law, and healthcare, and why evals and error analysis define expert-level agent development.

The Netflix Microservices Myth: An Architecture Migration Misunderstood by an Entire Industry
The real story behind Netflix's cloud migration and microservices transformation — and why the entire industry copied the solution while missing the actual problem.