28.3 Advanced CDS Features and Custom Class Loaders
CDS supports advanced features including custom class loaders, module-aware archives, and AOT integration for maximum performance.
Custom Class Loaders Support
// Custom Class Loader CDS Support
public class CustomClassLoaderCDS {
public static void printCustomLoaderSupport() {
System.out.println("=== CUSTOM CLASS LOADER SUPPORT ===");
System.out.println("\n--- SUPPORTED LOADERS (JDK 11+) ---");
System.out.println("\n1. Bootstrap Class Loader:");
System.out.println(" • Loads JDK core classes (java.*)");
System.out.println(" • Always supported");
System.out.println(" • Default CDS archive");
System.out.println("\n2. Platform Class Loader:");
System.out.println(" • Loads JDK platform modules");
System.out.println(" • java.sql, java.xml, etc.");
System.out.println(" • Supported since JDK 11");
System.out.println("\n3. System Class Loader:");
System.out.println(" • Loads application classes");
System.out.println(" • Classes from classpath");
System.out.println(" • Supported since JDK 10");
System.out.println("\n4. Custom Class Loaders:");
System.out.println(" • User-defined loaders");
System.out.println(" • Requires explicit setup");
System.out.println(" • Supported since JDK 11");
System.out.println("\n--- CLASS LOADER HIERARCHY ---");
System.out.println("\n ┌──────────────────────┐");
System.out.println(" │ Bootstrap Loader │");
System.out.println(" │ (JDK core) │");
System.out.println(" └──────────┬───────────┘");
System.out.println(" │");
System.out.println(" ┌──────────▼───────────┐");
System.out.println(" │ Platform Loader │");
System.out.println(" │ (JDK modules) │");
System.out.println(" └──────────┬───────────┘");
System.out.println(" │");
System.out.println(" ┌──────────▼───────────┐");
System.out.println(" │ System Loader │");
System.out.println(" │ (Application) │");
System.out.println(" └──────────┬───────────┘");
System.out.println(" │");
System.out.println(" ┌──────────▼───────────┐");
System.out.println(" │ Custom Loader │");
System.out.println(" │ (Plugin system) │");
System.out.println(" └──────────────────────┘");
System.out.println("\n--- REQUIREMENTS FOR CUSTOM LOADERS ---");
System.out.println("\nLoader must:");
System.out.println(" 1. Be registered during dump");
System.out.println(" 2. Load classes deterministically");
System.out.println(" 3. Use same classpath at runtime");
System.out.println(" 4. Be created before archive loading");
}
public static void printCustomLoaderExample() {
System.out.println("\n=== CUSTOM LOADER EXAMPLE ===");
System.out.println("\n--- SIMPLE PLUGIN LOADER ---");
System.out.println("\nPluginLoader.java:");
System.out.println(" public class PluginLoader extends URLClassLoader {");
System.out.println(" public PluginLoader(URL[] urls) {");
System.out.println(" super(urls, ");
System.out.println(" ClassLoader.getSystemClassLoader());");
System.out.println(" }");
System.out.println(" ");
System.out.println(" public static PluginLoader create(String path) {");
System.out.println(" try {");
System.out.println(" URL url = new File(path).toURI().toURL();");
System.out.println(" return new PluginLoader(new URL[]{url});");
System.out.println(" } catch (Exception e) {");
System.out.println(" throw new RuntimeException(e);");
System.out.println(" }");
System.out.println(" }");
System.out.println(" }");
System.out.println("\n--- CREATING ARCHIVE WITH CUSTOM LOADER ---");
System.out.println("\nStep 1 - Class list with loader info:");
System.out.println(" java -Xshare:off \\");
System.out.println(" -XX:DumpLoadedClassList=classes.lst \\");
System.out.println(" -cp app.jar:plugins/* \\");
System.out.println(" com.example.Main");
System.out.println("\nGenerated classes.lst includes loader info:");
System.out.println(" # System loader");
System.out.println(" com/example/Main");
System.out.println(" com/example/Service");
System.out.println(" ");
System.out.println(" # Custom plugin loader");
System.out.println(" @lambda-form-invoker");
System.out.println(" com/example/plugins/Plugin1 source: plugins/plugin1.jar");
System.out.println(" com/example/plugins/Plugin2 source: plugins/plugin2.jar");
System.out.println("\nStep 2 - Create archive:");
System.out.println(" java -Xshare:dump \\");
System.out.println(" -XX:SharedClassListFile=classes.lst \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -cp app.jar:plugins/*");
System.out.println("\nStep 3 - Use archive:");
System.out.println(" java -Xshare:on \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -cp app.jar:plugins/* \\");
System.out.println(" com.example.Main");
}
public static void printLoaderConstraints() {
System.out.println("\n=== CUSTOM LOADER CONSTRAINTS ===");
System.out.println("\n--- DETERMINISTIC LOADING ---");
System.out.println("\n✓ Works (deterministic):");
System.out.println(" public Class<?> loadClass(String name) {");
System.out.println(" if (name.startsWith(\"com.plugin.\")) {");
System.out.println(" return findClass(name); // Always same path");
System.out.println(" }");
System.out.println(" return super.loadClass(name);");
System.out.println(" }");
System.out.println("\n✗ Doesn't work (non-deterministic):");
System.out.println(" public Class<?> loadClass(String name) {");
System.out.println(" if (Math.random() > 0.5) { // Random!");
System.out.println(" return loadFromCache(name);");
System.out.println(" }");
System.out.println(" return loadFromDisk(name);");
System.out.println(" }");
System.out.println("\n--- CLASSPATH STABILITY ---");
System.out.println("\nArchive creation:");
System.out.println(" -cp app.jar:plugins/v1.jar:plugins/v2.jar");
System.out.println("\n✓ Runtime (same order):");
System.out.println(" -cp app.jar:plugins/v1.jar:plugins/v2.jar");
System.out.println("\n✗ Runtime (different order):");
System.out.println(" -cp app.jar:plugins/v2.jar:plugins/v1.jar");
System.out.println(" → CDS will be disabled");
System.out.println("\n--- LOADER LIFECYCLE ---");
System.out.println("\nLoader must exist before archive mapping:");
System.out.println(" public static void main(String[] args) {");
System.out.println(" // 1. Create custom loader FIRST");
System.out.println(" PluginLoader loader = PluginLoader.create(\"plugins\");");
System.out.println(" ");
System.out.println(" // 2. JVM maps CDS archive");
System.out.println(" // 3. Classes from archive reference loader");
System.out.println(" ");
System.out.println(" // 4. Use classes");
System.out.println(" Class<?> plugin = loader.loadClass(\"Plugin\");");
System.out.println(" }");
}
}
Module-Aware CDS
// Module-Aware CDS
public class ModuleCDS {
public static void printModuleCDS() {
System.out.println("=== MODULE-AWARE CDS ===");
System.out.println("\n--- MODULES IN CDS ---");
System.out.println("\nDefault archive includes:");
System.out.println(" • java.base module (always)");
System.out.println(" • Core JDK classes");
System.out.println(" • ~1,300 classes");
System.out.println("\nAdditional modules:");
System.out.println(" • java.sql");
System.out.println(" • java.xml");
System.out.println(" • java.logging");
System.out.println(" • java.management");
System.out.println(" • Your application modules");
System.out.println("\n--- INCLUDING APPLICATION MODULES ---");
System.out.println("\nModule structure:");
System.out.println(" myapp/");
System.out.println(" ├── module-info.java");
System.out.println(" ├── com/example/Main.java");
System.out.println(" └── com/example/Service.java");
System.out.println("\nmodule-info.java:");
System.out.println(" module com.example.myapp {");
System.out.println(" requires java.base;");
System.out.println(" requires java.sql;");
System.out.println(" exports com.example;");
System.out.println(" }");
System.out.println("\n--- CREATING MODULE ARCHIVE ---");
System.out.println("\nStep 1 - Generate class list:");
System.out.println(" java -Xshare:off \\");
System.out.println(" -XX:DumpLoadedClassList=classes.lst \\");
System.out.println(" --module-path mods \\");
System.out.println(" -m com.example.myapp/com.example.Main");
System.out.println("\nStep 2 - Create archive:");
System.out.println(" java -Xshare:dump \\");
System.out.println(" -XX:SharedClassListFile=classes.lst \\");
System.out.println(" -XX:SharedArchiveFile=myapp.jsa \\");
System.out.println(" --module-path mods \\");
System.out.println(" -m com.example.myapp/com.example.Main");
System.out.println("\nStep 3 - Use archive:");
System.out.println(" java -Xshare:on \\");
System.out.println(" -XX:SharedArchiveFile=myapp.jsa \\");
System.out.println(" --module-path mods \\");
System.out.println(" -m com.example.myapp/com.example.Main");
System.out.println("\n--- DYNAMIC MODULE CDS ---");
System.out.println("\nSimpler with dynamic CDS:");
System.out.println(" java -XX:ArchiveClassesAtExit=myapp.jsa \\");
System.out.println(" --module-path mods \\");
System.out.println(" -m com.example.myapp/com.example.Main");
System.out.println("\n--- MODULE LAYERS ---");
System.out.println("\nLayer 1 - JDK modules:");
System.out.println(" Default classes.jsa");
System.out.println(" Contains: java.base, java.sql, java.xml");
System.out.println("\nLayer 2 - Application modules:");
System.out.println(" myapp.jsa (layered on default)");
System.out.println(" Contains: com.example.myapp");
System.out.println("\nUsage:");
System.out.println(" java -XX:SharedArchiveFile=default.jsa:myapp.jsa \\");
System.out.println(" --module-path mods \\");
System.out.println(" -m com.example.myapp/com.example.Main");
}
}
CDS with AOT Compilation
// CDS and AOT Integration
public class CDSWithAOT {
public static void printCDSAOTIntegration() {
System.out.println("=== CDS WITH AOT COMPILATION ===");
System.out.println("\n--- WHAT IS AOT? ---");
System.out.println("\nAhead-of-Time Compilation:");
System.out.println(" • Compile Java bytecode to native code");
System.out.println(" • Before application runs");
System.out.println(" • Skip JIT warmup");
System.out.println(" • Instant peak performance");
System.out.println("\n--- CDS + AOT BENEFITS ---");
System.out.println("\nCDS provides:");
System.out.println(" ✓ Fast class loading");
System.out.println(" ✓ Shared metadata");
System.out.println(" ✓ Reduced memory footprint");
System.out.println("\nAOT provides:");
System.out.println(" ✓ No JIT compilation delay");
System.out.println(" ✓ Immediate peak performance");
System.out.println(" ✓ Predictable execution");
System.out.println("\nCombined:");
System.out.println(" ✓ Fastest possible startup");
System.out.println(" ✓ Instant peak performance");
System.out.println(" ✓ Minimal memory usage");
System.out.println(" ✓ Perfect for short-lived processes");
System.out.println("\n--- USING GRAALVM NATIVE IMAGE ---");
System.out.println("\nGraalVM Native Image:");
System.out.println(" • Compile entire app to native executable");
System.out.println(" • Includes AOT and CDS-like features");
System.out.println(" • Startup: <50ms");
System.out.println(" • Memory: <50MB RSS");
System.out.println("\nBuild native image:");
System.out.println(" native-image \\");
System.out.println(" -cp app.jar:lib/* \\");
System.out.println(" --no-fallback \\");
System.out.println(" -H:+ReportExceptionStackTraces \\");
System.out.println(" com.example.Main");
System.out.println("\nResult:");
System.out.println(" • Standalone executable");
System.out.println(" • No JVM required");
System.out.println(" • CDS metadata embedded");
System.out.println(" • All code AOT compiled");
System.out.println("\n--- PROJECT LEYDEN (FUTURE) ---");
System.out.println("\nOpenJDK Project Leyden goals:");
System.out.println(" • Tight CDS + AOT integration");
System.out.println(" • Profile-guided optimizations");
System.out.println(" • Cached JIT compilations");
System.out.println(" • Sub-50ms startup");
System.out.println("\nPlanned features:");
System.out.println(" • Pre-compiled method cache");
System.out.println(" • Closed-world optimizations");
System.out.println(" • Eliminated runtime overhead");
System.out.println(" • Expected: JDK 23-25");
}
}
Advanced Configuration
// Advanced CDS Configuration
public class AdvancedCDSConfig {
public static void printAdvancedOptions() {
System.out.println("=== ADVANCED CDS OPTIONS ===");
System.out.println("\n--- ARCHIVE SIZE TUNING ---");
System.out.println("\nDefault sizes:");
System.out.println(" -XX:SharedBaseAddress=0x800000000");
System.out.println(" -XX:SharedReadOnlySize=16M");
System.out.println(" -XX:SharedReadWriteSize=16M");
System.out.println(" -XX:SharedMiscDataSize=4M");
System.out.println("\nFor large applications:");
System.out.println(" java -Xshare:dump \\");
System.out.println(" -XX:SharedReadOnlySize=32M \\");
System.out.println(" -XX:SharedReadWriteSize=32M \\");
System.out.println(" -XX:SharedMiscDataSize=8M \\");
System.out.println(" -XX:SharedClassListFile=classes.lst \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -cp app.jar:lib/*");
System.out.println("\n--- COMPRESSED OOP SETTINGS ---");
System.out.println("\nWith compressed oops (default, heap <32GB):");
System.out.println(" java -XX:+UseCompressedOops \\");
System.out.println(" -XX:SharedArchiveFile=app-coop.jsa \\");
System.out.println(" -jar app.jar");
System.out.println("\nWithout compressed oops (heap >32GB):");
System.out.println(" java -XX:-UseCompressedOops \\");
System.out.println(" -XX:SharedArchiveFile=app-nocoop.jsa \\");
System.out.println(" -jar app.jar");
System.out.println("\nNote: Archive must match oop setting!");
System.out.println("\n--- VERIFICATION LEVELS ---");
System.out.println("\nNo verification (fastest):");
System.out.println(" java -Xverify:none \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -jar app.jar");
System.out.println(" ⚠ Use only for trusted code");
System.out.println("\nRemote verification (default):");
System.out.println(" java -Xverify:remote \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -jar app.jar");
System.out.println(" Balance of speed and safety");
System.out.println("\n--- STRING DEDUPLICATION ---");
System.out.println("\nEnable string dedup with CDS:");
System.out.println(" java -XX:+UseStringDeduplication \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -jar app.jar");
System.out.println("\nBenefits:");
System.out.println(" • Shared string table");
System.out.println(" • Reduced duplicate strings");
System.out.println(" • Lower memory usage");
System.out.println("\n--- DIAGNOSTIC LOGGING ---");
System.out.println("\nComprehensive CDS logging:");
System.out.println(" java -Xlog:cds=debug \\");
System.out.println(" -Xlog:cds+map=trace \\");
System.out.println(" -Xlog:cds+resolve=debug \\");
System.out.println(" -XX:SharedArchiveFile=app.jsa \\");
System.out.println(" -jar app.jar");
System.out.println("\nLogging options:");
System.out.println(" cds General CDS info");
System.out.println(" cds+map Memory mapping");
System.out.println(" cds+resolve Class resolution");
System.out.println(" cds+load Class loading");
System.out.println(" cds+heap Heap archiving");
}
public static void printTroubleshooting() {
System.out.println("\n=== TROUBLESHOOTING CDS ===");
System.out.println("\n--- COMMON ISSUES ---");
System.out.println("\n1. Archive not used silently:");
System.out.println(" Problem: -Xshare:auto falls back without warning");
System.out.println(" Solution: Use -Xshare:on to force error");
System.out.println(" Debug: -Xlog:cds shows reason");
System.out.println("\n2. Classpath mismatch:");
System.out.println(" Error: 'Unable to use shared archive'");
System.out.println(" Cause: Runtime classpath differs from dump");
System.out.println(" Solution: Ensure exact same -cp");
System.out.println("\n3. JVM option mismatch:");
System.out.println(" Error: 'The shared archive file's option setting'");
System.out.println(" Cause: Different -XX flags between dump and run");
System.out.println(" Solution: Match flags or regenerate");
System.out.println("\n4. Compressed oops mismatch:");
System.out.println(" Error: 'The shared archive file cannot be used'");
System.out.println(" Cause: Archive created with different oop setting");
System.out.println(" Solution: Regenerate with matching setting");
System.out.println("\n5. Version mismatch:");
System.out.println(" Error: 'Cannot use shared archive'");
System.out.println(" Cause: JDK version changed");
System.out.println(" Solution: Regenerate for new JDK");
System.out.println("\n--- VERIFICATION ---");
System.out.println("\nConfirm CDS is active:");
System.out.println(" java -Xlog:cds -version 2>&1 | grep 'Opened'");
System.out.println(" ");
System.out.println(" Expected output:");
System.out.println(" [info][cds] Opened archive /path/to/app.jsa");
System.out.println("\nCheck class loading:");
System.out.println(" java -Xlog:cds+load -jar app.jar 2>&1 | grep 'loaded'");
System.out.println(" ");
System.out.println(" Shows classes loaded from archive");
}
}
Best Practices
- Test custom loaders thoroughly: Ensure deterministic behavior.
- Use module-aware archives: Leverage JPMS for better organization.
- Consider AOT for serverless: CDS + Native Image for fastest startup.
- Layer archives strategically: Share common layers across services.
- Monitor archive effectiveness: Use diagnostic logging.
- Handle mismatches gracefully: Provide fallback or clear errors.
- Document loader requirements: Custom loaders need careful setup.
- Tune archive sizes: Adjust for large applications.
- Keep compressed oop setting consistent: Match between dump and runtime.
- Plan for future enhancements: Project Leyden will improve CDS + AOT integration.