skip to content

Class Data Sharing (CDS)

Class Data Sharing archives the loaded classes from a training run so subsequent JVM starts skip much of the loading work. The cheapest startup win available, and the one to mention before native.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

What is Class Data Sharing (CDS), and how does it speed up JVM / Spring Boot startup without going native?

level: juniorimportance: should knowfreq 25%

answer

  1. Snapshot parsed classes -> memory-map at start
  2. AppCDS = your + library classes, not just JDK
  3. Still a normal JVM: reflection/proxies/JIT intact
  4. ~2x startup, no closed-world unlike native
  5. spring.context.exit=onRefresh training run

basics

~20 s

CDS stores parsed class metadata in an archive file that the JVM memory-maps at startup instead of re-parsing and re-verifying each class. A Spring Boot app starts roughly twice as fast while staying a normal JVM app.

solid answer

~50 s

Class Data Sharing takes the in-memory representation of loaded classes (parsed bytecode, verification data, method metadata) and writes it to an on-disk archive. On the next start the JVM memory-maps that archive instead of finding, reading, parsing and verifying every class again, so startup drops sharply — typically around 2x for a Spring Boot app. AppCDS extends this from JDK classes to your application and library classes. Crucially, the app is still a fully dynamic JVM: reflection, dynamic proxies, JIT, agents and conditional beans all work unchanged. That makes CDS a low-risk middle ground between a plain JVM and a GraalVM native image — you get faster startup and lower per-instance memory with none of native image's closed-world constraints or long build times. Spring Boot 3.3+ has first-class support, and CDS composes with AOT for further gains.

code

java · 13 lines
java
// Nothing special in code — CDS is a runtime/JVM concern.
// A standard Spring Boot entry point is all CDS needs:
@org.springframework.boot.autoconfigure.SpringBootApplication
public class Application {
    public static void main(String[] args) {
        org.springframework.boot.SpringApplication.run(Application.class, args);
    }
}
// Training run (loads classes, then exits before serving):
//   java -Dspring.context.exit=onRefresh \
//        -XX:ArchiveClassesAtExit=application.jsa -jar app.jar
// Production run (uses the archive):
//   java -XX:SharedArchiveFile=application.jsa -jar app.jar

go deeper

for a junior

Know that CDS caches loaded class metadata in a file the JVM maps at startup, giving faster startup while staying a normal JVM.

for a middle

Should distinguish AppCDS/dynamic CDS from the old static JDK archive and name the archive-then-use flow.

for a senior

Frames CDS as the low-risk alternative to native image and knows Spring Boot's training-run integration.

for a principal

Can position CDS in a startup/footprint strategy (CDS + AOT vs native) and reason about ops constraints like classpath/JDK stability.

## The problem CDS solves When a JVM starts an application it must, for every class it touches: locate the `.class` bytes on the classpath, read them, **parse** them into internal structures, **verify** them (bytecode safety checks), and build metadata (constant pool, method tables, etc.). For a large Spring Boot app that is thousands of classes on every single start — pure repeated work, identical run to run. **Class Data Sharing (CDS)** does that work once, snapshots the resulting in-memory class metadata into an **archive file** (conventionally `*.jsa`), and on later starts the JVM **memory-maps** the archive directly into its address space. Memory-mapping is near-instant and the mapped region can be shared read-only across multiple JVM processes on the same host, which also lowers total memory. ### Static CDS vs AppCDS vs Dynamic CDS - **Static CDS** (very old) archived only core JDK classes. Modern JDKs (13+) even ship a default JDK archive out of the box. - **Application CDS (AppCDS)** extends archiving to your *application* and *third-party library* classes — this is what matters for Spring Boot, where most classes are Spring/your code, not `java.*`. - **Dynamic CDS** (JDK 13, JEP 350) removes the tedious old step of hand-writing a class list: the JVM simply records the classes actually loaded during a run and dumps them at exit. This is the mechanism Spring Boot uses. ### What you actually gain - Startup: commonly ~2x faster for Spring Boot (exact numbers vary by app). - Memory: shared, mapped metadata reduces per-instance footprint. ### What you keep (the key selling point vs native image) CDS is **still an ordinary HotSpot JVM**. Everything dynamic works: reflection, `java.lang.reflect.Proxy` / CGLIB proxies, runtime classpath scanning, `@Conditional` beans decided at runtime, Java agents, full JIT compilation and profile-guided optimization. There is **no closed-world assumption** and **no long AOT/native build** — you don't need reachability metadata or `reflect-config.json`. Compared to a **GraalVM native image**, CDS starts slower (native is tens of milliseconds) but is far cheaper to adopt, keeps peak throughput via JIT, and imposes none of native's restrictions. ### How you enable it (dynamic CDS, the common path) 1. **Training run** — produce the archive from a real (or Spring-Boot-orchestrated) run: `-XX:ArchiveClassesAtExit=application.jsa`. 2. **Production run** — use it: `-XX:SharedArchiveFile=application.jsa`. JDK 19+ collapses both into one flag, `-XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=application.jsa`. ### Spring Boot 3.3+ integration Spring Boot adds a **training-run mode** via `-Dspring.context.exit=onRefresh`, which starts the context, loads all the classes needed to bootstrap, then exits before serving traffic — perfect for populating an archive. Paketo/Spring Boot buildpacks can do the whole training-run-and-archive step at image-build time via `BP_JVM_CDS_ENABLED=true`. ### Gotchas - The **classpath and JDK version must match** between the training run and the production run; a mismatch invalidates the archive. - CDS works best with an **extracted/exploded** jar layout (stable classpath) rather than surprises from the nested fat-jar classloader; Spring Boot's `java -Djarmode=tools -jar app.jar extract` produces exactly that layout. - CDS speeds up **startup**, not steady-state throughput (JIT still governs peak performance). - `-Xshare:auto` (default) silently runs without the archive if it can't be used; `-Xshare:on` fails loudly instead — useful to prove CDS is actually engaged.

  • Does CDS make the app as fast to start as a GraalVM native image?
    No. Native image starts in tens of milliseconds; CDS is roughly 2x faster than a cold JVM but still on the order of hundreds of ms to seconds. CDS trades some startup speed for zero closed-world constraints and no long build.
  • Does CDS improve peak throughput?
    Not really. It shortens startup and can lower memory, but steady-state throughput is still driven by the JIT, which behaves the same as a normal JVM.

saying these in an interview costs you the question

  • Claiming CDS makes the app native / removes the JVM
  • Saying CDS needs reflect-config.json like native image
  • Believing CDS boosts steady-state throughput rather than startup
  • Thinking CDS only archives JDK classes (that is old static CDS, not AppCDS)

context

open as a page

Walk through the dynamic CDS flags: what do -XX:ArchiveClassesAtExit and -XX:SharedArchiveFile each do, and in what order?

level: middleimportance: should knowfreq 22%

basics

~10 s

First a training run with -XX:ArchiveClassesAtExit=app.jsa dumps an archive of the classes loaded, when the JVM exits. Then production runs pass -XX:SharedArchiveFile=app.jsa to memory-map and reuse that archive for faster startup.

open as a page

How does Spring Boot's training-run archive work, and what does -Dspring.context.exit=onRefresh do?

level: seniorimportance: should knowfreq 20%

basics

~10 s

-Dspring.context.exit=onRefresh tells Spring Boot to start the context, finish refreshing (all beans created, classes loaded), then exit the JVM before serving traffic. Run it with -XX:ArchiveClassesAtExit to capture those classes into a CDS archive.

open as a page

When would you choose CDS over a GraalVM native image (or plain JVM) for a Spring Boot service, and how do CDS and AOT relate?

level: principalimportance: should knowfreq 16%

basics

~20 s

Choose CDS when you want faster startup and lower memory but must keep full JVM dynamism (reflection, proxies, agents) and cheap, fast builds. Native image starts far faster but has a closed-world model and long builds. CDS and AOT are complementary and stack on the JVM.

open as a page

What does -XX:+AutoCreateSharedArchive do, and how does it change the CDS workflow versus the manual two-step approach?

level: seniorimportance: nice to knowfreq 12%

basics

~20 s

-XX:+AutoCreateSharedArchive (JDK 19+), used with -XX:SharedArchiveFile=app.jsa, makes one flag do both jobs: if the archive is missing or stale it creates it at exit, and if it's valid it uses it. No separate training-run flag needed.

open as a page