VMware offers training and certification to turbo-charge your progress.Learn more
As a follow-up to the Runtime efficiency with Spring blog post, I am happy to share that our exploration of Project Leyden optimizations has led to some interesting discoveries regarding the JDK's little-used CDS ("Class Data Sharing") feature and has materialized into a new feature that we have been able to ship in Spring Framework 6.1.
As stated in the official documentation, Class Data Sharing (CDS) helps reduce the startup time and memory footprint of JVMs by caching class metadata in an archive file so that it can be quickly pre-loaded into a newly launched JVM. This accelerates class loading, a significant contributor to startup time. A default CDS archive is pre-packaged with most recent JDK distributions to contain metadata for common JDK classes. You can also create customized CDS archives to speed up the loading of classes in your own applications.
Let’s discover what CDS can bring to your Spring applications!
Spring Framework 6.1 brings a new Class Data Sharing documentation section explaining the 2 steps process of optimizing an application:
-Dspring.context.exit=onRefresh JVM system property, which does not require starting the beans or having access to the remote services for most use cases.
For CDS optimizations to be fully effective, you have to make sure that the JDK and classpath used by the commands that create the archive and start the application are identical. Note also that, to effectively cache classes:
* wildcard character expansion.
As Spring Boot executable JARs or documented unpacked deployments for now do not fulfill all those conditions, they do not allow optimal CDS performances yet.
That’s why, without making any assumption on what may be done in Spring Boot to support CDS in a more integrated fashion, we have been working with Stéphane Nicoll on a CDS-friendly unpacked deployment, to be able to get relevant data points and provide a way for Spring developers to explore CDS support. See more details in the related spring-boot#38276 issue.
If you want to use CDS on your application and provide feedback, you can try and take inspiration from the spring-cds-demo repository, which contains a self-contained unpack-executable-jar.sh script that unpacks a Spring Boot executable JAR in a way that allows optimal CDS performances. You can also try the great cds-log-parser tools created by Stéphane, to generate reports indicating which classes are loaded from the CDS cache.
Let’s see what we can learn from data points of the famous Spring Petclinic application deployed with those CDS optimizations running on Java 21 and optionally combined with Spring AOT optimizations.
The first takeaway is unrelated to CDS and already well-known and documented, but it is worth highlighting: production deployment of Spring Boot applications should be unpacked for optimal startup time. If you are using Buildpacks, that’s already the case. If not, you may want to check and potentially refine your custom deployment.
CDS optimizations reduce the startup time by 30% to 35% compared to unpack deployment, with only the small constraints to create a CDS archive of a few dozens of Mb and to ship it along to your application. Of course, the gain is not as dramatic as it is with GraalVM or Project CRaC, but you also don't have to do a lot of work to get this benefit. So, properly integrated, CDS may have great potential for wide adoption. If you combine CDS with Spring AOT optimizations, you can reduce the startup time of Petclinic by 36% to 42%.
As usual, we are looking for feedback from the Spring community to feed our reflection about the potential next steps for a more integrated experience. For example, would you be interested in the ability to automatically build Spring Boot optimized containers with a CDS cache?
On a more forward looking note, the Spring team continues to collaborate with the Java Platform team to see how we can leverage those improvements and findings with Project Leyden premain optimizations, to push the boundaries of what is possible in terms of runtime efficiency on the JVM while reducing as much as possible the constraints for Spring developers and operators.