28.1 CDS Fundamentals and Architecture

Class Data Sharing (CDS) is a JVM feature that significantly improves startup time and reduces memory footprint by pre-processing and sharing class metadata across multiple JVM instances.

What is CDS?

// CDS Fundamentals
public class CDSFundamentals {

    public static void printCDSOverview() {
        System.out.println("=== CLASS DATA SHARING (CDS) OVERVIEW ===");

        System.out.println("\n--- WHAT IS CDS? ---");

        System.out.println("\nDefinition:");
        System.out.println("  CDS allows class metadata to be shared between");
        System.out.println("  multiple JVM processes running the same application.");

        System.out.println("\n--- HOW IT WORKS ---");

        System.out.println("\n1. Traditional Class Loading (Without CDS):");
        System.out.println("   ┌──────────────┐");
        System.out.println("   │   JVM #1     │  • Load .class files");
        System.out.println("   │              │  • Parse bytecode");
        System.out.println("   │ Parse        │  • Verify classes");
        System.out.println("   │ Verify       │  • Create metadata");
        System.out.println("   │ Build Meta   │  • Store in memory");
        System.out.println("   └──────────────┘  Time: ~500ms");
        System.out.println("   ");
        System.out.println("   ┌──────────────┐");
        System.out.println("   │   JVM #2     │  • Repeat all steps");
        System.out.println("   │              │  • Duplicate work");
        System.out.println("   │ Parse        │  • Separate memory");
        System.out.println("   │ Verify       │");
        System.out.println("   │ Build Meta   │");
        System.out.println("   └──────────────┘  Time: ~500ms");

        System.out.println("\n2. With CDS:");
        System.out.println("   ┌──────────────┐");
        System.out.println("   │ CDS Archive  │  • Pre-processed classes");
        System.out.println("   │   (.jsa)     │  • Ready-to-use metadata");
        System.out.println("   │              │  • Memory-mapped file");
        System.out.println("   └──────┬───────┘");
        System.out.println("          │ mmap");
        System.out.println("      ┌───┴────┬────────┐");
        System.out.println("      ▼        ▼        ▼");
        System.out.println("   JVM #1   JVM #2   JVM #3");
        System.out.println("   Time: ~50ms per JVM");
        System.out.println("   Memory: Shared across all JVMs");

        System.out.println("\n--- KEY BENEFITS ---");

        System.out.println("\n1. Faster Startup:");
        System.out.println("   • Skip class parsing");
        System.out.println("   • Skip verification");
        System.out.println("   • Skip metadata construction");
        System.out.println("   • Typical improvement: 10-40%");

        System.out.println("\n2. Reduced Memory Footprint:");
        System.out.println("   • Class metadata shared via memory mapping");
        System.out.println("   • One copy in physical RAM");
        System.out.println("   • Multiple JVMs reference same pages");
        System.out.println("   • Typical savings: 20-50MB per JVM");

        System.out.println("\n3. Better Resource Utilization:");
        System.out.println("   • Less page cache pressure");
        System.out.println("   • Improved CPU cache utilization");
        System.out.println("   • Reduced I/O during startup");
    }

    public static void printCDSArchitecture() {
        System.out.println("\n=== CDS ARCHITECTURE ===");

        System.out.println("\n--- SHARED ARCHIVE STRUCTURE ---");

        System.out.println("\nA .jsa file contains:");

        System.out.println("\n1. Class Metadata:");
        System.out.println("   • Klass structures (internal representation)");
        System.out.println("   • Method metadata");
        System.out.println("   • Field information");
        System.out.println("   • Constant pool entries");

        System.out.println("\n2. Bytecode:");
        System.out.println("   • Pre-verified bytecode");
        System.out.println("   • Ready for execution");
        System.out.println("   • No verification needed");

        System.out.println("\n3. String Table:");
        System.out.println("   • Interned strings");
        System.out.println("   • Shared across JVM instances");

        System.out.println("\n4. Symbol Table:");
        System.out.println("   • Method names");
        System.out.println("   • Field names");
        System.out.println("   • Class names");

        System.out.println("\n--- MEMORY MAPPING ---");

        System.out.println("\nHow CDS uses memory mapping:");

        System.out.println("\n1. Archive Loading:");
        System.out.println("   • JVM calls mmap() system call");
        System.out.println("   • Maps .jsa file into process address space");
        System.out.println("   • No physical copy to RAM initially");

        System.out.println("\n2. On-Demand Paging:");
        System.out.println("   • Pages loaded as accessed");
        System.out.println("   • OS handles page faults");
        System.out.println("   • Shared pages across processes");

        System.out.println("\n3. Copy-on-Write:");
        System.out.println("   • Shared pages are read-only");
        System.out.println("   • Modifications trigger COW");
        System.out.println("   • Modified pages become private");

        System.out.println("\n--- METADATA REGIONS ---");

        System.out.println("\nCDS archive has multiple regions:");

        System.out.println("\nRead-Only (RO) Region:");
        System.out.println("  • Class metadata");
        System.out.println("  • Method metadata");
        System.out.println("  • Immutable data");
        System.out.println("  • Fully shareable");

        System.out.println("\nRead-Write (RW) Region:");
        System.out.println("  • Mutable class data");
        System.out.println("  • Initially shared");
        System.out.println("  • COW on modification");

        System.out.println("\nMetadata (MD) Region:");
        System.out.println("  • Symbol table");
        System.out.println("  • String table");
        System.out.println("  • Dictionary");
    }

    public static void printDefaultCDS() {
        System.out.println("\n=== DEFAULT CDS ARCHIVE ===");

        System.out.println("\n--- JDK INCLUDES DEFAULT ARCHIVE ---");

        System.out.println("\nSince JDK 12:");
        System.out.println("  • Default CDS archive included");
        System.out.println("  • Contains JDK core classes");
        System.out.println("  • ~1,300 classes from java.base");
        System.out.println("  • Enabled by default");

        System.out.println("\nLocation:");
        System.out.println("  $JAVA_HOME/lib/server/classes.jsa");
        System.out.println("  (or classes_nocoops.jsa without compressed oops)");

        System.out.println("\n--- DEFAULT ARCHIVE USAGE ---");

        System.out.println("\nAutomatic (default):");
        System.out.println("  java -Xshare:auto MyApp");
        System.out.println("  ");
        System.out.println("  Behavior:");
        System.out.println("    • Try to use default archive");
        System.out.println("    • Fall back if unavailable");
        System.out.println("    • Silently disable on mismatch");

        System.out.println("\nForce enabled:");
        System.out.println("  java -Xshare:on MyApp");
        System.out.println("  ");
        System.out.println("  Behavior:");
        System.out.println("    • Require CDS archive");
        System.out.println("    • Fail if not available");
        System.out.println("    • Error on mismatch");

        System.out.println("\nDisabled:");
        System.out.println("  java -Xshare:off MyApp");
        System.out.println("  ");
        System.out.println("  Behavior:");
        System.out.println("    • Don't use CDS");
        System.out.println("    • Traditional class loading");
        System.out.println("    • Useful for troubleshooting");

        System.out.println("\n--- VERIFYING DEFAULT ARCHIVE ---");

        System.out.println("\nCheck if CDS is active:");
        System.out.println("  java -Xlog:cds -version");

        System.out.println("\nExpected output:");
        System.out.println("  [info][cds] Opened archive /path/to/classes.jsa");
        System.out.println("  [info][cds] Mapped 1234 classes from archive");

        System.out.println("\n--- WHAT'S INCLUDED ---");

        System.out.println("\nDefault archive contains:");
        System.out.println("  • java.lang.* classes");
        System.out.println("  • java.util.* classes");
        System.out.println("  • java.io.* classes");
        System.out.println("  • Other java.base module classes");
        System.out.println("  • JDK internal classes");

        System.out.println("\nNOT included:");
        System.out.println("  • Application classes");
        System.out.println("  • Third-party libraries");
        System.out.println("  • Other JDK modules (java.sql, etc.)");
        System.out.println("  → Use AppCDS for these");
    }
}

CDS vs AppCDS

// CDS vs AppCDS Comparison
public class CDSComparison {

    public static void printCDSvsAppCDS() {
        System.out.println("=== CDS vs APPCDS ===");

        System.out.println("\n--- CDS (Class Data Sharing) ---");

        System.out.println("\nScope:");
        System.out.println("  • JDK classes only");
        System.out.println("  • java.base module");
        System.out.println("  • ~1,300 core classes");

        System.out.println("\nSetup:");
        System.out.println("  • Included with JDK");
        System.out.println("  • No configuration needed");
        System.out.println("  • Enabled by default");

        System.out.println("\nBenefit:");
        System.out.println("  • Small startup improvement (5-10%)");
        System.out.println("  • Modest memory savings");

        System.out.println("\n--- APPCDS (Application CDS) ---");

        System.out.println("\nScope:");
        System.out.println("  • JDK classes");
        System.out.println("  • Application classes");
        System.out.println("  • Third-party libraries");
        System.out.println("  • Custom class loaders");

        System.out.println("\nSetup:");
        System.out.println("  • Requires archive creation");
        System.out.println("  • Training run needed");
        System.out.println("  • Manual configuration");

        System.out.println("\nBenefit:");
        System.out.println("  • Significant startup improvement (20-40%)");
        System.out.println("  • Substantial memory savings");
        System.out.println("  • Critical for microservices");

        System.out.println("\n--- WHEN TO USE EACH ---");

        System.out.println("\nUse default CDS (automatic):");
        System.out.println("  ✓ Single JVM instance");
        System.out.println("  ✓ No special requirements");
        System.out.println("  ✓ Quick development/testing");

        System.out.println("\nUse AppCDS (manual setup):");
        System.out.println("  ✓ Multiple JVM instances");
        System.out.println("  ✓ Containerized deployments");
        System.out.println("  ✓ Microservices architecture");
        System.out.println("  ✓ Startup time critical");
        System.out.println("  ✓ Memory constrained");
    }
}

When CDS Cannot Be Used

// CDS Limitations
public class CDSLimitations {

    public static void printLimitations() {
        System.out.println("=== CDS LIMITATIONS ===");

        System.out.println("\n--- CONDITIONS THAT DISABLE CDS ---");

        System.out.println("\n1. Agent Modifications:");
        System.out.println("   -javaagent:agent.jar");
        System.out.println("   ");
        System.out.println("   • Java agents can modify classes");
        System.out.println("   • Shared metadata would be incorrect");
        System.out.println("   • CDS automatically disabled");

        System.out.println("\n2. Incompatible Flags:");
        System.out.println("   -Xverify:all");
        System.out.println("   -XX:+UseAppCDS with -Xshare:off");
        System.out.println("   ");
        System.out.println("   • Some flags conflict with CDS");
        System.out.println("   • Full verification incompatible");

        System.out.println("\n3. Classpath Mismatch:");
        System.out.println("   • Archive created with classpath A");
        System.out.println("   • Running with classpath B");
        System.out.println("   • Classes don't match");
        System.out.println("   • CDS disabled for safety");

        System.out.println("\n4. JVM Version Mismatch:");
        System.out.println("   • Archive from JDK 17.0.1");
        System.out.println("   • Running on JDK 17.0.2");
        System.out.println("   • Internal structures changed");
        System.out.println("   • Must regenerate archive");

        System.out.println("\n--- CLASS LOADER RESTRICTIONS ---");

        System.out.println("\nBefore JDK 11:");
        System.out.println("  • Only bootstrap class loader");
        System.out.println("  • No custom class loaders");
        System.out.println("  • No platform class loader");

        System.out.println("\nJDK 11+ (AppCDS improvements):");
        System.out.println("  • Bootstrap class loader ✓");
        System.out.println("  • Platform class loader ✓");
        System.out.println("  • System class loader ✓");
        System.out.println("  • Custom class loaders ✓ (with setup)");

        System.out.println("\n--- BEST PRACTICES ---");

        System.out.println("\n✓ DO:");
        System.out.println("  • Regenerate after JDK updates");
        System.out.println("  • Regenerate after classpath changes");
        System.out.println("  • Test with -Xshare:on to catch issues");
        System.out.println("  • Document archive creation process");

        System.out.println("\n✗ DON'T:");
        System.out.println("  • Reuse archive across JDK versions");
        System.out.println("  • Ignore -Xshare:on failures");
        System.out.println("  • Use with bytecode instrumentation");
        System.out.println("  • Share archive across different apps");
    }
}

Measuring CDS Impact

// Measuring CDS Benefits
public class CDSMeasurement {

    public static void measureStartupTime() {
        System.out.println("=== MEASURING STARTUP TIME ===");

        System.out.println("\n--- WITHOUT CDS ---");
        System.out.println("time java -Xshare:off -cp app.jar com.example.Main");
        System.out.println("Result: 2.5 seconds");

        System.out.println("\n--- WITH CDS ---");
        System.out.println("time java -Xshare:on -XX:SharedArchiveFile=app.jsa \\");
        System.out.println("     -cp app.jar com.example.Main");
        System.out.println("Result: 1.8 seconds");

        System.out.println("\nImprovement: 28% faster startup");
    }

    public static void measureMemoryUsage() {
        System.out.println("\n=== MEASURING MEMORY FOOTPRINT ===");

        System.out.println("\n--- SINGLE JVM (no benefit) ---");

        System.out.println("\nWithout CDS:");
        System.out.println("  Resident memory: 120 MB");

        System.out.println("\nWith CDS:");
        System.out.println("  Resident memory: 118 MB");
        System.out.println("  (Minimal difference for single instance)");

        System.out.println("\n--- MULTIPLE JVMS (significant benefit) ---");

        System.out.println("\n5 JVMs without CDS:");
        System.out.println("  Per-process: 120 MB × 5 = 600 MB");
        System.out.println("  Shared: ~50 MB");
        System.out.println("  Total physical RAM: ~550 MB");

        System.out.println("\n5 JVMs with CDS:");
        System.out.println("  Per-process: 105 MB × 5 = 525 MB");
        System.out.println("  Shared: ~90 MB (CDS archive + text)");
        System.out.println("  Total physical RAM: ~435 MB");

        System.out.println("\nSavings: 115 MB (21% reduction)");

        System.out.println("\n--- MEASUREMENT TOOLS ---");

        System.out.println("\nLinux:");
        System.out.println("  ps -o pid,rss,vsz,comm -p <pid>");
        System.out.println("  pmap -x <pid> | grep jsa");
        System.out.println("  cat /proc/<pid>/smaps | grep -A 15 classes.jsa");

        System.out.println("\nmacOS:");
        System.out.println("  vmmap <pid> | grep classes.jsa");

        System.out.println("\nJVM flags:");
        System.out.println("  -Xlog:cds+map=trace");
        System.out.println("  Shows memory region mapping");
    }
}

Best Practices

  • Use default CDS: Enabled automatically, provides baseline benefits.
  • Consider AppCDS for microservices: Significant gains with multiple instances.
  • Regenerate after updates: Archive tied to specific JDK version and classpath.
  • Test with -Xshare:on: Catch configuration issues early.
  • Monitor with logging: Use -Xlog:cds to verify archive usage.
  • Combine with other optimizations: CDS + AOT + profile-guided optimization.
  • Document creation process: Automate archive generation in CI/CD.
  • Measure actual impact: Benchmark startup time and memory in your environment.
  • Include in container images: Pre-generate archive during image build.
  • Keep archives small: Only include frequently-used classes.