textlize pricing account
Java 21 ⮕ 25: Performance and Runtime Enhancements #RoadTo25
Cover

00:17:00

Java 21 to 25: Unlocking Performance and Runtime Gains

The journey from Java Development Kit (JDK) 21 to JDK 25 brings significant enhancements in performance, garbage collection, and observability tools. These updates address critical issues like virtual thread pinning and introduce features like compact object headers, making Java applications faster, more efficient, and easier to monitor. Here’s a detailed look at what’s new.

Virtual Threads: No More Pinning Issues

Virtual threads, introduced in JDK 21, were designed to improve scalability by allowing lightweight concurrency. However, a known issue occurred when virtual threads encountered blocking operations inside synchronized blocks or methods—they would pin the underlying platform thread, hindering scalability. This problem was highlighted in real-world scenarios, such as those reported by Netflix.

JDK 24 resolved this with JEP 491: "Synchronized Virtual Threads Without Pinning." Upgrading to JDK 25 includes this fix, ensuring virtual threads properly release platform threads during synchronized blocks, eliminating a major obstacle for high-concurrency applications.

Performance Improvements: Startup and Throughput

JDK 25 delivers noticeable performance gains over JDK 21, even without code changes. Testing with the Spring Boot Pet Clinic application shows:

  • Startup time: Reduced from over 2.6 seconds on JDK 21 to around 2.4–2.5 seconds on JDK 25.
  • Throughput: Using load testing tools, cold runs improved from ~6,500 requests to ~7,500 requests, and warm runs from ~8,500 to ~10,500 requests—a 15–20% increase in throughput.

These improvements stem from cumulative optimizations across JDK versions, including string handling enhancements (e.g., JEP 451: String Deduplication in JDK 25) and garbage collector tweaks. However, results vary based on application architecture and workload.

Memory Usage and Heap Considerations

JDK 25 may use more heap memory by default due to optimistic internal heuristics. In tests, committed heap space increased from ~400 MB on JDK 21 to ~480 MB on JDK 25. Setting a max heap size (e.g., 400 MB) had minimal impact on throughput, as actual usage remained around 240–250 MB. This suggests that while JDK 25 is more aggressive with memory allocation, it can be managed with appropriate JVM flags.

Compact Object Headers: Saving Memory

A new feature in JDK 25, compact object headers (from Project Liliput), reduces the size of object headers on 64-bit HotSpot JVMs from 128 bits to 64 bits. This can decrease heap usage and garbage collection pressure, potentially lowering latency. Enable it with the -XX:+CompactObjectHeaders flag.

However, performance impacts are mixed: throughput may decrease in some cases due to object layout changes. It’s recommended to test this feature based on your application’s needs, weighing memory savings against throughput requirements.

ZGC Garbage Collector: Generational Mode Only

ZGC now exclusively uses generational mode in JDK 25, deprecating the single-generation mode introduced in JDK 21. Generational ZGC improves CPU and memory efficiency for most web applications, offering shorter pause times—often in the microsecond range—at the cost of slightly reduced throughput. This makes it ideal for latency-sensitive environments like microservices.

In tests, ZGC processed ~6,300 requests compared to G1GC’s ~7,500, but pause times were significantly shorter, enhancing user experience in responsive applications.

JDK Flight Recorder (JFR): Enhanced Observability

JFR is a built-in diagnostic tool for tracking performance issues, resource leaks, and method execution with minimal overhead. JDK 25 adds two key updates:

  • JEP 518: Cooperative Sampling improves stability.
  • JEP 520: Method Timing and Tracing allows configurable events for method execution time and call stack tracing without code changes.

For example, to trace Spring Data methods, use commands like method-timing or method-trace with fully qualified method names. JFR’s low impact makes it suitable for continuous production monitoring.

Conclusion

Upgrading to JDK 25 brings tangible benefits: fixed virtual threads, better performance, memory optimizations, and advanced observability with JFR. While some features like compact object headers require testing, the overall improvements make it a worthwhile update for most Java applications.

© 2025 textlize.com. all rights reserved. terms of services privacy policy