Archive for June, 2025
[Oracle Dev Days 2025] Optimizing Java Performance: Choosing the Right Garbage Collector
Jean-Philippe BEMPEL , a seasoned developer at Datadog and a Java Champion, delivered an insightful presentation on selecting and tuning Garbage Collectors (GCs) in OpenJDK to enhance Java application performance. His talk, rooted in practical expertise, unraveled the complexities of GCs, offering a roadmap for developers to align their choices with specific application needs. By dissecting the characteristics of various GCs and their suitability for different workloads, Jean-Philippe provided actionable strategies to optimize memory management, reduce production issues, and boost efficiency.
Understanding Garbage Collectors in OpenJDK
Garbage Collectors are pivotal in Java’s memory management, silently handling memory allocation and reclamation. However, as Jean-Philippe emphasized, a misconfigured GC can lead to significant performance bottlenecks in production environments. OpenJDK offers a suite of GCs—Serial GC, Parallel GC, G1, Shenandoah, and ZGC—each designed with distinct characteristics to cater to diverse application requirements. The challenge lies in selecting the one that best matches the workload, whether it prioritizes throughput or low latency.
Jean-Philippe began by outlining the foundational concepts of GCs, particularly the generational model. Most GCs in OpenJDK are generational, dividing memory into the Young Generation (for short-lived objects) and the Old Generation (for longer-lived objects). The Young Generation is further segmented into the Eden space, where new objects are allocated, and Survivor spaces, which hold objects that survive initial collections before promotion to the Old Generation. Additionally, the Metaspace stores class metadata, a critical but often overlooked component of memory management.
Serial GC: Simplicity for Constrained Environments
The Serial GC, one of the oldest collectors, operates with a single thread and employs a stop-the-world approach, pausing all application threads during collection. Jean-Philippe highlighted its suitability for small-scale applications, particularly those running in containers with less than 2 GB of RAM, where it serves as the default GC. Its simplicity makes it ideal for environments with limited resources, but its stop-the-world nature can introduce noticeable pauses, making it less suitable for latency-sensitive applications.
To illustrate, Jean-Philippe explained the mechanics of the Young Generation’s Survivor spaces. These spaces, S0 and S1, alternate roles as source and destination during minor GC cycles, copying live objects to manage memory efficiently. Objects surviving multiple cycles are promoted to the Old Generation, reducing the overhead of frequent collections. This generational approach leverages the hypothesis that most objects die young, minimizing the cost of memory reclamation.
Parallel GC: Maximizing Throughput
For applications prioritizing throughput, such as batch processing jobs, the Parallel GC offers significant advantages. Unlike the Serial GC, it leverages multiple threads to reclaim memory, making it efficient for systems with ample CPU cores. Jean-Philippe noted that it was the default GC until JDK 8 and remains a strong choice for throughput-oriented workloads like Spark jobs, Kafka consumers, or ETL processes.
The Parallel GC, also stop-the-world, excels in scenarios where total execution time matters more than individual pause durations. Jean-Philippe shared a benchmark using a JFR (Java Flight Recorder) file parsing application, where Parallel GC outperformed others, achieving a throughput of 97% (time spent in application versus GC). By tuning the Young Generation size to reduce frequent minor GCs, developers can further minimize object copying, enhancing overall performance.
G1 GC: Balancing Throughput and Latency
The G1 (Garbage-First) GC, default since JDK 9 for heaps larger than 2 GB, strikes a balance between throughput and latency. Jean-Philippe described its region-based memory management, dividing the heap into smaller regions (Eden, Survivor, Old, and Humongous for large objects). This structure allows G1 to focus on regions with the most garbage, optimizing memory reclamation with minimal copying.
In his benchmark, G1 showed a throughput of 85%, with average pause times of 76 milliseconds, aligning with its target of 200 milliseconds. However, Jean-Philippe pointed out challenges with Humongous objects, which can increase GC frequency if not managed properly. By adjusting region sizes (up to 32 MB), developers can mitigate these issues, improving throughput for applications like batch jobs while maintaining reasonable pause times.
Shenandoah and ZGC: Prioritizing Low Latency
For latency-sensitive applications, such as HTTP servers or microservices, Shenandoah and ZGC are the go-to choices. These concurrent GCs minimize pause times, often below a millisecond, by performing most operations alongside the running application. Jean-Philippe highlighted Shenandoah’s non-generational approach (though a generational version is in development) and ZGC’s generational support since JDK 21, making the latter particularly efficient for large heaps.
In a latency-focused benchmark using a Spring PetClinic application, Jean-Philippe demonstrated that Shenandoah and ZGC maintained request latencies below 200 milliseconds, significantly outperforming Parallel GC’s 450 milliseconds at the 99th percentile. ZGC’s use of colored pointers and load/store barriers ensures rapid memory reclamation, allowing regions to be freed early in the GC cycle, a key advantage over Shenandoah.
Tuning Strategies for Optimal Performance
Tuning GCs is as critical as selecting the right one. For Parallel GC, Jean-Philippe recommended sizing the Young Generation to reduce the frequency of minor GCs, ideally exceeding 50% of the heap to minimize object copying. For G1, adjusting region sizes can address Humongous object issues, while setting a maximum pause time target (e.g., 50 milliseconds) can shift its behavior toward latency sensitivity, though it may not compete with Shenandoah or ZGC in extreme cases.
For concurrent GCs like Shenandoah and ZGC, ensuring sufficient heap size and CPU cores prevents allocation stalls, where threads wait for memory to be freed. Jean-Philippe emphasized that Shenandoah requires careful heap sizing to avoid full GCs, while ZGC’s rapid region reclamation reduces such risks, making it more forgiving for high-allocation-rate applications.
Selecting the Right GC for Your Workload
Jean-Philippe concluded by categorizing workloads into two types: throughput-oriented (SPOT) and latency-sensitive. For SPOT workloads, such as batch jobs or ETL processes, Parallel GC or G1 are optimal, with Parallel GC offering easier tuning for predictable performance. For latency-sensitive applications, like microservices or databases (e.g., Cassandra), ZGC’s generational efficiency and Shenandoah’s low-pause capabilities shine, with ZGC being particularly effective for large heaps.
By analyzing workload characteristics and leveraging tools like GC Easy for log analysis, developers can make informed GC choices. Jean-Philippe’s benchmarks underscored the importance of tailoring GC configurations to specific use cases, ensuring both performance and stability in production environments.
Links:
Hashtags: #Java #GarbageCollector #OpenJDK #Performance #Tuning #Datadog #JeanPhilippeBempel #OracleDevDays2025
(temporary testing) Mapping pages
- [DevoxxFR] Kill Your Branches, Do Feature Toggles
- [DevoxxFR] An Ultrasonic Adventure!
- [DevoxxFR] How to be a Tech Lead in an XXL Pizza Team Without Drowning
- [DevoxxFR 2017] Why Your Company Should Store All Its Code in a Single Repo
- [DevoxxFR 2017] Introduction to the Philosophy of Artificial Intelligence
- [DevoxxFR 2017] Terraform 101: Infrastructure as Code Made Simple
- [DevoxxFR 2018] Deploying Microservices on AWS: Compute Options Explored at Devoxx France 2018
- [DevoxxFR 2018] Software Heritage: Preserving Humanity's Software Legacy
- [DevoxxFR 2018] Apache Kafka: Beyond the Brokers – Exploring the Ecosystem
- [DevoxxFR 2018] Are you "merge" or "rebase" oriented?
- A Decade of Devoxx FR and Java Evolution: A Detailed Retrospective and Forward-Looking Analysis
- [DevoxxFR 2022] Exploiter facilement des fonctions natives avec le Projet Panama depuis Java
- Kafka Streams @ Carrefour : Traitement big data à la vitesse de l’éclair
- [DevoxxFR 2022] Père Castor 🐻, raconte-nous une histoire (d’OPS)
- [DevoxFR 2022] Cracking Enigma: A Tale of Espionage and Mathematics
- [VivaTech 2021] Tech to Rethink Our Workplace at VivaTech 2021
- [VivaTech 2021] Emmanuel Macron : Championing European Scale-Ups and Innovation
- [DevoxxFR 2021] Maximizing Productivity with Programmable Ergonomic Keyboards: Insights from Alexandre Navarro
- [Devoxx FR 2021] IoT Open Source at Home
- [VivaTech 2019] Funding and Growing Tomorrow's Unicorns
- [VivaTech 2019] What's Your Next Bet
- [Devoxx France 2021] Overcoming Impostor Syndrome: Practical Tips
- [VivaTech 2018] How VCs Are Growing Tomorrow's Euro-corns
- [ScalaDays 2019] Techniques for Teaching Scala
- Kotlin Native Concurrency Explained by Kevin Galligan
- [DevoxxFR 2018] Java in Docker: Best Practices for Production
- [DevoxxFR 2018] Watch Out! Don't Plug in That USB, You Might Get Seriously Hacked!
- Gradle: A Love-Hate Journey at Margot Bank
- Navigating the Application Lifecycle in Kubernetes
- [DevoxxFR 2019] Back to Basics: Stop Wasting Time with Dates
- "All Architects !": Empowering Every Developer as an Architect
- Navigating the Challenges of Legacy Systems
- "A monolith, or nothing!": Embracing the Monolith at Ornikar
- Event Sourcing Without a Framework: A Practical Approach
- [DevoxxFR 2023] Hexagonal Architecture in 15 Minutes: Simplifying Complex Systems
- [DevoxxFR 2023] Tests, an Investment for the Future: Building Reliable Software
- Ce que l’open source peut apprendre des startups : Une perspective nouvelle
- Et si on parlait un peu de sécurité ? Un guide pour les développeurs
- Navigating the Reactive Frontier: Oleh Dokuka’s Reactive Streams at Devoxx France 2023
- Meet with Others: tools for speech
- Gestion des incidents : Parler et agir
- Decoding Shazam: Unraveling Music Recognition Technology
- [AWS Summit Berlin 2023] Go-to-Market with Your Startup: Tips and Best Practices from VC Investors
- [KotlinConf'23] The Future of Kotlin is Bright and Multiplatform
- [KotlinConf'2023] Coroutines and Loom: A Deep Dive into Goals and Implementations
- [GopherCon UK 2022] Leading in Tech
- [Spring I/O 2023] Multitenant Mystery: Only Rockers in the Building by Thomas Vitale
- [Spring I/O 2023] Do You Really Need Hibernate?
- [Spring I/O 2023] Managing Spring Boot Application Secrets: Badr Nass Lahsen
- [KotlinConf2023] Java and Kotlin: A Mutual Evolution
- A Tricky Java Question
- SnowFlake❄: Why does SUM() return NULL instead of 0?
- JpaSystemException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
- SpringBatch: How to have different schedules, per environment, for instance: keep the fixedDelay=60000 in prod, but schedule with a Cron expression in local dev?
- 🚀 Making Spring AOP Work with Struts 2: A Powerful Combination! 🚀
- 🚀 Mastering Flyway Migrations with Maven
- [Devoxx FR 2024] Instrumenting Java Applications with OpenTelemetry: A Comprehensive Guide
- [Devoxx FR 2024] Mastering Reproducible Builds with Apache Maven: Insights from Hervé Boutemy
- Understanding Dependency Management and Resolution: A Look at Java, Python, and Node.js
- [PyData Paris 2024] Exploring Quarto Dashboard for Impactful and Visual Communication
- Onyxia: A User-Centric Interface for Data Scientists in the Cloud Age
- Boosting AI Reliability: Uncertainty Quantification with MAPIE
- Predictive Modeling and the Illusion of Signal
- Building Intelligent Data Products at Scale
- Renovate/Dependabot: How to Take Control of Dependency Updates
- [PyData Global 2024] Making Gaussian Processes Useful
- [AWS Summit Paris 2024] Winning Fundraising Strategies for 2024
- [DevoxxFR 2024] Super Tech’Rex World: The Assembler Strikes Back
- [KotlinConf2024] Hacking Sony Cameras with Kotlin
- [DevoxxFR 2024] Going AOT: Mastering GraalVM for Java Applications
- Java's Emerging Role in AI and Machine Learning: Bridging the Gap to Production
- CTO Perspective: Choosing a Tech Stack for Mainframe Rebuild
- Elastic APM: When to Use @CaptureSpan vs. @CaptureTransaction?
- How to Bypass Elasticsearch’s 10,000-Result Limit with the Scroll API
- Problem: Spring JMS MessageListener Stuck / Not Receiving Messages
- Efficient Inter-Service Communication with Feign and Spring Cloud in Multi-Instance Microservices
- Mastering DNS Configuration: A, AAAA, CNAME, and Best Practices with OVH
- Advanced Encoding in Java, Kotlin, Node.js, and Python
- Understanding volatile in Java: A Deep Dive with a Cloud-Native Use Case
- Quick and dirty script to convert WordPress export file to Blogger / Atom XML
- Why Project Managers Must Guard Against “Single Points of Failure” in Human Capital
- RSS to EPUB Converter: Create eBooks from RSS Feeds
- Essential Security Considerations for Docker Networking
- CTO's Wisdom: Feature Velocity Over Premature Scalability in Early-Stage Startups
- AWS S3 Warning: “No Content Length Specified for Stream Data” – What It Means and How to Fix It
- The CTO's Tightrope Walk: Deeper into the Hire vs. Outsource Dilemma
- Understanding Chi-Square Tests: A Comprehensive Guide for Developers
- Creating EPUBs from Images: A Developer's Guide to Digital Publishing
- The Fractional CTO: A Strategic Ally or a Risky Gamble?
- Orchestrating Progress: A CTO's Strategy for Balancing Innovation and Stability
- 🚀 Making Spring AOP Work with Struts 2: A Powerful Combination! 🚀
- Bridging the Divide: CTO Communication with Aliens (aka: Non-Technical Stakeholders)
- 5 Classic Software Security Holes Every Developer Should Know
- Advanced Java Security: 5 Critical Vulnerabilities and Mitigation Strategies
- Using Redis as a Shared Cache in AWS: Architecture, Code, and Best Practices
- 🗄️ AWS S3 vs. MinIO – Choosing the Right Object Storage
- Demystifying Parquet: The Power of Efficient Data Storage in the Cloud
- ️ Prototype Pollution: The Silent JavaScript Vulnerability You Shouldn’t Ignore
- Mastering Information Structure: A Deep Dive into Lists and Nested Lists Across Document Formats
- Applications Web with Spring Boot 2.0
- Script to clean WSL and remove Ubuntu from Windows 11
- [Oracle Dev Days 2025] From JDK 21 to JDK 25: Jean-Michel Doudoux on Java’s Evolution
[Oracle Dev Days 2025] From JDK 21 to JDK 25: Jean-Michel Doudoux on Java’s Evolution
Jean-Michel Doudoux, a renowned Java Champion and Sciam consultant, delivered a session, charting Java’s evolution from JDK 21 to JDK 25. As the next Long-Term Support (LTS) release, JDK 25 introduces transformative features that redefine Java development. Jean-Michel’s talk provided a comprehensive guide to new syntax, APIs, JVM enhancements, and security measures, equipping developers to navigate Java’s future with confidence.
Enhancing Syntax and APIs
Jean-Michel began by exploring syntactic improvements that streamline Java code. JEP 456 in JDK 22 introduces unnamed variables using _
, improving clarity for unused variables. JDK 23’s JEP 467 adds Markdown support for Javadoc, easing documentation. In JDK 25, JEP 511 simplifies module imports, while JEP 512’s implicit classes and simplified main methods make Java more beginner-friendly. JEP 513 enhances constructor flexibility, enabling pre-constructor logic. These changes collectively minimize boilerplate, boosting developer efficiency.
Expanding Capabilities with New APIs
The session highlighted APIs that broaden Java’s scope. The Foreign Function & Memory API (JEP 454) enables safer native code integration, replacing sun.misc.Unsafe
. Stream Gatherers (JEP 485) enhance data processing, while the Class-File API (JEP 484) simplifies bytecode manipulation. Scope Values (JEP 506) improve concurrency with lightweight alternatives to thread-local variables. Jean-Michel’s practical examples demonstrated how these APIs empower developers to craft modern, robust applications.
Strengthening JVM and Security
Jean-Michel emphasized JVM and security advancements. JEP 472 in JDK 25 restricts native code access via --enable-native-access
, enhancing system integrity. The deprecation of sun.misc.Unsafe
aligns with safer alternatives. The removal of 32-bit support, the Security Manager, and certain JMX features reflects Java’s modern focus. Performance boosts in HotSpot JVM, Garbage Collectors (G1, ZGC), and startup times via Project Leyden (JEP 483) ensure Java’s competitiveness.
Boosting Productivity with Tools
Jean-Michel covered enhancements to Java’s tooling ecosystem, including upgraded Javadoc, JCMD, and JAR utilities, which streamline workflows. New Java Flight Recorder (JFR) events improve diagnostics. He urged developers to test JDK 25’s early access builds to prepare for the LTS release, highlighting how these tools enhance efficiency and scalability in application development.
Navigating JDK 25’s LTS Future
Jean-Michel wrapped up by emphasizing JDK 25’s role as an LTS release with extended support. He encouraged proactive engagement with early access programs to adapt to new features and deprecations. His session offered a clear, actionable roadmap, empowering developers to leverage JDK 25’s innovations confidently. Jean-Michel’s expertise illuminated Java’s trajectory, inspiring attendees to embrace its evolving landscape.
Links:
Hashtags: #Java #JDK25 #LTS #JVM #Security #Sciam #JeanMichelDoudoux
Script to clean WSL and remove Ubuntu from Windows 11
Here is a fully automated PowerShell script that will:
-
Unregister and remove all WSL distros
-
Reset WSL to factory defaults
-
Optionally reinstall WSL cleanly (commented out)
⚠️ You must run this script as Administrator
# ===================================================== # WSL Full Reset Script for Windows 11 # Removes all distros and resets WSL system features # MUST BE RUN AS ADMINISTRATOR # ===================================================== Write-Host "`n== STEP 1: List and remove all WSL distros ==" -ForegroundColor Cyan $distros = wsl --list --quiet foreach ($distro in $distros) { Write-Host "Unregistering WSL distro: $distro" -ForegroundColor Yellow wsl --unregister "$distro" } Start-Sleep -Seconds 2 Write-Host "`n== STEP 2: Disable WSL-related Windows features ==" -ForegroundColor Cyan dism.exe /online /disable-feature /featurename:VirtualMachinePlatform /norestart dism.exe /online /disable-feature /featurename:Microsoft-Windows-Subsystem-Linux /norestart Start-Sleep -Seconds 2 Write-Host "`n== STEP 3: Uninstall WSL kernel update (if present) ==" -ForegroundColor Cyan $wslUpdate = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like "*Microsoft.WSL2*" } if ($wslUpdate) { winget uninstall --id "Microsoft.WSL2" --silent } else { Write-Host "No standalone WSL kernel update found." -ForegroundColor DarkGray } Start-Sleep -Seconds 2 Write-Host "`n== STEP 4: Clean leftover configuration files ==" -ForegroundColor Cyan $paths = @( "$env:USERPROFILE\.wslconfig", "$env:APPDATA\Microsoft\Windows\WSL", "$env:LOCALAPPDATA\Packages\CanonicalGroupLimited*", "$env:LOCALAPPDATA\Docker", "$env:USERPROFILE\.docker" ) foreach ($path in $paths) { Write-Host "Removing: $path" -ForegroundColor DarkYellow Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $path } Write-Host "`n== STEP 5: Reboot Required ==" -ForegroundColor Magenta Write-Host "Please restart your computer to complete the WSL reset process." # Optional: Reinstall WSL cleanly (after reboot) # Uncomment the lines below if you want the script to also reinstall WSL <# Write-Host "`n== STEP 6: Reinstall WSL ==" -ForegroundColor Cyan wsl --install #>