JDK 27 takes shape, while GraalVM changes the release cadence - JVM Weekly vol. 176
GraalVM switches to monthly releases (and sparks a discussion about JVMCI), Valhalla finally leaves the lab, and JDK 27 EA brings a whole load of improvements.
Welcome to another edition. This week it’s all about the ecosystem internals - lots of movement on both the GraalVM and OpenJDK fronts. And interestingly, these two threads are starting to intertwine - so let’s begin with the biggest organizational shift.
1. GraalVM Overhauls Its Delivery Model - and Amazon Fights for JVMCI’s Future
GraalVM is making a fundamental change to its delivery model on two fronts simultaneously. First, the project drops its independent versioning (remember those confusing 22.3, 23.0 numbers?) in favor of JDK-aligned labels like “GraalVM for JDK 21,” following the JEP 223 scheme - though this had already been creeping into the naming for a while. Second - and this is the bolder move - GraalVM shifts from quarterly to monthly feature releases.
The main driver is - of course - the need to ship AI-targeted compiler optimizations faster (hehe) along with developer tooling improvements. For JVM engineers, this means a much shorter feedback loop, especially around Native Image and polyglot environments. On the flip side, it forces a strategic choice: adopt the monthly cadence and get incremental functional iterations, or stay on quarterly CPU (Critical Patch Updates) and miss the latest optimizations. In other words, GraalVM is creating two tracks: a “fast lane” for teams that can keep up with testing, and a “stability lane” for those who prefer the proven quarterly security patch cycle. Sound familiar? It’s the same dilemma OpenJDK solved with its feature release / LTS split - just on a far more compressed timescale.
Because in 2026, everything is faster. At this rate, by 2028 we’ll be doing daily releases.
On the technical side - under the GraalVM Free Terms and Conditions (GFTC), advanced performance optimizations and G1 GC support, previously locked behind the Enterprise paywall, are now available in the free distribution. This significantly lowers the barrier for production Native Image deployments. If someone ever told you “GraalVM Native Image isn’t production-ready without Enterprise” - that excuse just expired.
There’s also a notable caveat in the roadmap: GraalVM plans to skip support for JDK 26, 27, and 28 (non-LTS versions), targeting Java 29 directly. For teams still on the 22.3.x line, this is a clear signal to migrate to a JDK 17 or 21 baseline - sooner rather than later. Aggressive sunsetting of older branches combined with an accelerated release cadence creates pressure not every enterprise will be ready for.
And it’s precisely in this context that a parallel discussion deserves attention - JDK-8382582, proposing the removal of the experimental JVMCI (Java-Level JVM Compiler Interface) from OpenJDK. HotSpot maintainers argue, not unreasonably, that JVMCI introduces significant codebase complexity and testing overhead for a feature that remains niche outside the GraalVM ecosystem.
Makes sense, right? The problem? Amazon has formally opposed it. This isn’t sentiment - their engineers report heavy reliance on Graal JIT and the Truffle framework to scale polyglot applications in production on HotSpot. And this is no small player - we’re talking AWS-scale, Corretto, and the entire ecosystem Amazon builds around the JVM.
To understand the stakes, a quick step back. JVMCI is an experimental API introduced in JDK 9 that opens HotSpot’s internal compilation pipeline to external implementations. Normally, when HotSpot decides a code path is “hot” enough for native compilation, it hands it to one of its built-in compilers: C1 (fast compilation, less optimization) or C2 (slower compilation, aggressive optimization). JVMCI lets you plug any Java-written compiler into that slot - and that’s exactly how Graal JIT works. Instead of C2, HotSpot passes the code’s intermediate representation to the Graal compiler via JVMCI, and Graal returns compiled machine code. This is what lets you run Graal as a drop-in C2 replacement on stock OpenJDK - no full GraalVM distribution needed.
JVMCI is also the foundation for Truffle - the framework that lets you implement interpreters for new languages (JavaScript, Python, Ruby, R, LLVM bitcode) and automatically get JIT compilation through partial evaluation. Without JVMCI, the entire “polyglot on HotSpot” model stops working.
The community points to Project Detroit as the “eventual successor” for JIT integration, but Amazon counters that Detroit is years from production-grade performance and stability. This isn’t a “just migrate” situation - we’re talking about live stacks serving real traffic. In a significant move, Amazon has offered to assume JVMCI maintenance responsibilities (!) - no small commitment in the OpenJDK world.
If JVMCI disappears before Detroit matures, organizations running Graal on HotSpot face a choice: GraalVM CE or a compiler stack refactor. Neither is painless.
2. Project Valhalla: From Erasure to Specialized Generics
A deep-dive article appeared on inside.java - Beyond Erasure: Project Valhalla’s Path to Specialized Generics - and it’s probably the best explanation to date of where Project Valhalla (JEP 401/402) is heading and how it plans to get there.
I know, I know - “Valhalla is coming” is a running gag in JVM circles, right up there with “year of Linux on the desktop.” But this article shows we’re dealing with something far more concrete than another promise.
The piece starts with the problem we all know: type erasure - the 2004 compromise that gave us generics but no type information at runtime. Today, C2 manages with Class Hierarchy Analysis (CHA) to eliminate redundant checkcast and speculative devirtualization. It works... okay. But it’s patching, not solving.
The article details the “Parametric VM” architecture - a fundamentally different approach to generics. Instead of erasing type information at compile time and hoping the JIT can recover it, the Parametric VM introduces a runtime “Specializer” that generates dedicated class variants for specific memory layouts. Think of it as the JVM creating a purpose-built List implementation specifically for int values - not a generic List<Object> that wraps each int in an Integer box.
This is what enables “Universal Generics”: List<int> bypasses java.lang.Integer boxing entirely. Primitives are stored directly in arrays and object fields, flattened inline alongside regular objects - no object headers per element, no pointer indirection, no chasing references across the heap. Data sits sequentially in memory, which is exactly what modern CPUs want for cache performance. The results described in the article reflect this: 60–80% memory footprint reduction and significantly improved L1 cache hit rates. Approaching C++/Rust performance territory while keeping managed runtime safety guarantees. The numbers speak for themselves.
And lest this sound like just theory and conference talks - PR #31120 has been opened with the JEP 401 implementation (Value Classes and Objects). The scale is impressive: ~3,000 commits, ~2,000 modified classes.
Before you start planning a migration, though - Brian Goetz cautions against timeline optimism. Given the mid-June rampdown and the rigorous security reviews required for such a fundamental type system change, JDK 27 is an unlikely integration target. But the sheer fact that this RFR exists - at this scale - represents the most significant movement toward flattened memory layouts in Java’s history. After a decade of waiting, I see light at the end of the tunnel. And this time it doesn’t look like an oncoming train (heh).
3. JDK 27 Early Access
JDK 27 EA is shaping up as a release worth serious attention - especially for production quality-of-life. It’s not a single-headline release (that’s still waiting on Valhalla), but the sum of individual JEPs tells a remarkably coherent story of modernizing JVM defaults. Let’s walk through the highlights, because a lot of detail has landed recently.
Memory First: G1 Everywhere + Compact Headers
JEP 523: Make G1 the Default Garbage Collector in All Environments retires the “server-class machine” heuristic dating back to J2SE 5.0 (yes, 2004 - same era as type erasure, appreciate the poetry). Until now, the JVM on machines with <2 CPUs or <1792MB RAM defaulted to the Serial Collector - which in the era of micro-containers with 512MB RAM limits meant a good chunk of production workloads got a GC never designed for them. G1 is now the default everywhere. No more GC log surprises after deploying to Kubernetes with aggressive resource limits.
In parallel, JEP 534: Compact Object Headers by Default enables compact object headers by default. Building on JEP 450: Compact Object Headers (Experimental), this reduces the standard object header from 12 to 8 bytes on 64-bit architectures by encoding the class pointer into the mark word. Sounds like an implementation detail? Perhaps. But for workloads that create lots of small objects (and which Java workload doesn’t?) it’s a 10–20% heap reduction and better CPU cache performance - out of the box, no flags needed.
It’s fascinating how quickly that one got from the concept to production default.
Security: JFR Finally Stops Leaking Your Secrets
JEP 536: JFR In-Process Data Redaction brings in-process data redaction to JDK Flight Recorder. And I have to say it bluntly: finally.
For years, JFR has been an invaluable production profiling tool - low overhead, rich telemetry, no external agent dependencies. But it carried a dirty secret (pun intended): database passwords, API tokens, and auth keys passed via environment variables or system properties ended up in .jfr files as plaintext. Anyone who’s ever run a security audit at an organization using JFR knows the moment - “wait, these credentials have been in diagnostic files... for two years... on a shared network drive?”

Redaction now operates at the JVM recording engine level - before data hits disk or gets emitted via the JFR Streaming API. Three targeted events: jdk.InitialSystemProperty, jdk.InitialEnvironmentVariable, and jdk.JVMInformation (command-line arguments). The shift from “redact after the fact” to “secure by default at source” is a major compliance win - especially for GDPR, SOC2, and similar regulations. It eliminates the need for custom sanitization scripts that - in my experience - half of teams forgot to configure on new environments anyway.
The only minor cost: debugging configuration issues that require seeing full property values gets slightly harder. But that’s a trade-off most enterprise architects will accept with open arms.
Diagnostics: jcmd Learns to Read Core Dumps
JEP 528: Post-Mortem Crash Analysis with jcmd extends jcmd with post-mortem analysis - finally letting you run familiar diagnostic commands (Thread.print, VM.info, VM.flags, VM.system_properties) against static core files from HotSpot crashes. Syntax: jcmd <executable> <corefile> <command>.
For those of you who’ve never had to reach for jhsdb at 3 AM during a production incident - congratulations, I wish you continued luck. For the rest of us - this bridges the gap between the friendly, well-known jcmd and the more complex, Serviceability Agent–based jhsdb. Until now, jcmd only worked with live JVM processes (PID or local socket). If the process died and left a core dump, you had to switch to a completely different tool with different syntax, conventions, and mental model. In containerized environments where JVM processes are ephemeral, this is even more painful - by the time you’d attach jcmd, the container was long recycled by the orchestrator.
JEP 528 doesn’t replace jhsdb (still essential for low-level memory inspection) or native debuggers like GDB. But it surfaces the most commonly needed JVM metadata through the standard, familiar interface - a significant convenience for production support and root-cause analysis.
macOS/x64 Deprecation: End of an Era
Oracle has officially signaled the end of macOS/x64 port maintenance - deprecation targets JDK 27, with eventual removal to follow. The argument is straightforward: Apple Silicon won, the transition succeeded, and maintaining the legacy Intel port demands full-time dedicated engineering that’s no longer justifiable.
Worth emphasizing - Oracle explicitly stated this is not a part-time job. It requires dedicated resources for feature parity and platform-specific bug fixing. The bar for a “credible third-party” successor is high, and no one has stepped up yet. The community is largely pragmatic about it - some voices suggest aligning JDK’s support window more closely with Apple’s own macOS x64 hardware lifecycle, but realistically, JDK 27 will likely be the first release where Intel Macs become legacy tier.
If you’re still relying on Intel Mac Pros or x64 macOS CI/CD runners - time to plan the migration. AArch64 macOS or Linux x64 environments are the two obvious paths.
Re-previews and Incubations: The Eternal Stabilization
Finally - the “eternal candidates,” each at a different point on the road to GA, but all sharing the same theme: the API is ready, the integration isn’t.
Structured Concurrency (JEP 533) enters its seventh(!) preview - easy to lose count since the feature has been evolving since JDK 19 (JEP 428). The main change this round is an API refinement toward fluent style: StructuredTaskScope.join() and joinUntil(Instant) now return the scope instance, enabling elegant chaining in try-with-resources blocks. Cosmetic? Perhaps. But it signals that core mechanics are settled (the major refactor happened in JDK 24/JEP 491) and the team is now polishing ergonomics. Seven previews suggest a cautious approach to API stability - which, after experiences with “premature GA” features (see: Nashorn), is welcome.
Vector API (JEP 537) hits its... twelfth incubation. Yes, twelfth. The API is effectively frozen - zero breaking changes this iteration - but graduation awaits Valhalla and its value classes with specialized generics. Without those, the Vector API can’t reach its final, memory-overhead-free form. For those already using SIMD via jdk.incubator.vector in production (with the --add-modules flag): nothing changes, your code will keep working.
Lazy Constants (JEP 531) in its third preview stabilizes a lazy initialization mechanism that lets HotSpot recognize and optimize lazily computed values as aggressively as static final - constant folding, inlining, the full arsenal. For years, developers relied on the “initialization-on-demand holder idiom” or volatile double-checked locking; these patterns work for concurrency but remain black boxes to the JIT. JEP 531 offers a declarative alternative that communicates semantics directly to the compiler. Third preview signals stabilization.
And finally JEP 538 PEM Encoder/Decoder - native PEM support in the Java Cryptography Architecture, handling PrivateKey, PublicKey, X509Certificate, and X509CRL. The most interesting technical detail: streaming-capable processing for efficient handling of large Certificate Revocation Lists without memory pressure. No more manual Base64, no more depending on Bouncy Castle just to handle RFC 7468.
Closing Note: The Lazy Collections Debate (JEP 526)
An interesting debate is brewing on amber-dev around JEP 526 (”Deferred Immutability”), worth watching even if it doesn’t land in JDK 27. The proposal introduces List.ofLazy / Map.ofLazy with mandatory memoization - simplifying immutable collection creation with on-demand computed values, thread-safety guarantees, and “compute-once” semantics.
The community, however, points to a serious limitation: hardcoded memoization prevents these APIs from serving as truly lazy functional views - à la Guava’s Lists.transform. The core objection? If every value must be memoized, you can’t handle collections larger than available heap, and simple type conversions (e.g., projecting a List<CharSequence> as List<String>) force unnecessary allocation. The debate centers on whether these methods should be simple convenience utilities for late-initialized data or a broader foundation for memory-efficient data processing. Consensus leans toward a non-caching default - and frankly, I agree.
----
PS: And greetings to all those in the KotlinConf. I couldn’t make it this year. However, my special reporter, Grzegorz Król, will bring you some news from the conference!







