skip to content

What happens to a CDS archive when the classpath or JDK changes, and how do you verify CDS is actually active at runtime?

level: seniorimportance: should knowfreq 22%

answer

  1. archive bound to classpath + JDK build
  2. mismatch -> silent fallback (auto)
  3. -Xshare:on = fail loudly / prove it's on
  4. -Xshare:off = disable, for A/B
  5. -Xlog:cds to diagnose

basics

~20 s

The archive is tied to the exact classpath and JDK it was built with. If either changes, the JVM detects a mismatch, ignores the archive, and falls back to normal class loading (no crash). Verify with -Xshare:on (fails if unusable) or -Xlog:cds logging.

solid answer

~50 s

A CDS archive captures a specific set of classes from a specific classpath, built by a specific JDK. At runtime the JVM validates the archive against the current classpath and JVM; if dependencies changed, the JDK version differs, or the classpath layout differs, the archive is considered stale and the JVM **silently falls back** to ordinary class loading — you lose the speedup but nothing breaks. That silent fallback is a gotcha: you can think CDS is on when it isn't. To *verify*, use `-Xshare:on`, which forces CDS and makes the JVM **fail to start** if the archive can't be mapped — good for catching regressions in tests/CI. `-Xshare:auto` (the default) uses the archive if valid and falls back otherwise; `-Xshare:off` disables CDS entirely. For diagnostics, `-Xlog:cds` (or `-Xlog:cds=debug`) prints whether the archive was used and why classes were or weren't loaded from it. Because of this coupling, you must **regenerate the archive** whenever you change dependencies or upgrade the JDK.

code

java · 12 lines
java
// Prove CDS is active (fail startup if archive unusable) — great for CI:
//   java -Xshare:on -XX:SharedArchiveFile=application.jsa -jar app/my-app.jar
//
// See exactly what CDS did:
//   java -Xlog:cds -XX:SharedArchiveFile=application.jsa -jar app/my-app.jar
//
// Measure the benefit by disabling CDS:
//   java -Xshare:off -jar app/my-app.jar
//
// Auto-create/refresh a stale archive (newer JDKs):
//   java -XX:+AutoCreateSharedArchive -XX:SharedArchiveFile=application.jsa \
//        -jar app/my-app.jar

go deeper

for a junior

Just know the archive can become stale and the app still runs without it.

for a middle

Know that changing dependencies or the JDK invalidates the archive and you must regenerate it.

for a senior

Explain silent fallback under -Xshare:auto, use -Xshare:on to enforce/verify, and -Xlog:cds to diagnose.

for a principal

Bake archive validation into CI (-Xshare:on), align build/runtime JDKs, treat the .jsa as a versioned build artifact, and consider AutoCreateSharedArchive for self-healing.

## Why the archive is fragile by design A `.jsa` archive stores the JVM's parsed metadata for a **specific class list resolved from a specific classpath**, dumped by a **specific JDK build**. For the memory-mapped metadata to be safe to reuse, the runtime environment must match what produced it. So the JVM records identifying information (JDK version/build, classpath entries and their state) and **validates** it at startup. Mismatches that invalidate (or partially invalidate) an archive include: - **JDK version/build change** — even a minor upgrade can change internal class-metadata layout. - **Classpath changes** — added/removed/updated dependency jars, or a different classpath order/layout. - **Different module/agent configuration** in some cases. ## The fallback is silent — the key gotcha Under the default `-Xshare:auto`, if the archive is invalid the JVM does **not** error. It just **ignores the archive and loads classes normally**. Your app still works — you simply lose the startup benefit, quietly. This is the classic trap: a dependency bump silently disables CDS and nobody notices the regression. ## The `-Xshare` modes - **`-Xshare:auto`** (default): use the archive if valid, otherwise fall back silently. - **`-Xshare:on`**: *require* CDS — if the archive can't be used, the JVM **refuses to start**. Use this in tests/CI to *prove* the archive is valid and catch regressions early. - **`-Xshare:off`**: disable CDS entirely (useful for A/B measuring the benefit). ## Diagnosing with unified logging Use JVM unified logging to see what CDS actually did: ``` java -Xlog:cds -XX:SharedArchiveFile=application.jsa -jar app/my-app.jar # or more detail: java -Xlog:cds=debug ... ``` This reports whether the shared archive was mapped, and can show classes that could not be loaded from the archive (e.g., because their source changed). ## Operational consequences 1. **Regenerate on every dependency or JDK change.** Treat the `.jsa` like a derived build artifact tied to a specific build input; rebuild it in the same pipeline that builds the jar. This is exactly why baking it in at build time (or via `BP_JVM_CDS_ENABLED=true` buildpacks) is preferred over hand-generating it once. 2. **Match the runtime JDK to the build JDK.** If your CI builds the archive with one JDK and the container runs a different one, CDS quietly disables. 3. **Verify in CI with `-Xshare:on`** so a stale archive fails loudly instead of degrading silently. 4. **Measure both ways** with `-Xshare:off` vs on to confirm the archive is delivering the expected startup reduction. ## Newer convenience: auto-create/refresh Modern JDKs also offer `-XX:+AutoCreateSharedArchive` combined with `-XX:SharedArchiveFile=app.jsa`, which creates the archive on first run and recreates it automatically if it becomes stale — reducing the manual regeneration burden, though a build-time archive is still the norm for production determinism.

  • Your startup times crept back up after a Spring dependency upgrade — what's the likely cause?
    The dependency change invalidated the CDS archive; under -Xshare:auto the JVM silently fell back to normal loading. Regenerate the archive from the new classpath and, ideally, run -Xshare:on in CI so it fails loudly next time.
  • How would you gate a build so a broken CDS archive can't ship?
    Add a smoke step that launches the app with -Xshare:on -XX:SharedArchiveFile=...; if the archive is stale or classpath-mismatched, the JVM refuses to start and the build fails.

saying these in an interview costs you the question

  • Claiming a classpath/JDK mismatch crashes the app — by default it just silently falls back.
  • Assuming one archive is valid forever across dependency and JDK upgrades.
  • Confusing -Xshare:on (require CDS) with -Xshare:off (disable CDS).
  • Not knowing there's any way to verify CDS is actually being used.

context