The HotSpot JVM uses two Just-In-Time (JIT) compilers: C1 (Client Compiler) and C2 (Server Compiler). Understanding their differences is crucial for performance tuning and optimization.
Architectural Overview
C1 (Client Compiler):
- Focus: Fast compilation, quick startup, low memory footprint
- Optimization Level: Light to medium optimizations
- Use Case: GUI applications, short-running processes
- Compilation Speed: Very fast
- Code Quality: Good enough for most cases
C2 (Server Compiler):
- Focus: Maximum performance, aggressive optimizations
- Optimization Level: Heavy optimizations
- Use Case: Long-running server applications
- Compilation Speed: Slower but produces highly optimized code
- Code Quality: Excellent, near-native performance
Compiler Architecture and Pipeline
package com.example.compiler; import java.lang.management.CompilationMXBean; import java.lang.management.ManagementFactory; /** * Demonstrates C1 and C2 compiler differences through practical examples */ public class CompilerDifferences { /** * Compiler architecture and pipeline comparison */ public static class CompilerArchitecture { // C1 Compiler Pipeline (Simplified) public static class C1Pipeline { public void compileMethod(byte[] bytecode) { System.out.println("C1 Compilation Pipeline:"); System.out.println("1. Parse bytecode and build HIR (High-level IR)"); System.out.println("2. Perform local optimizations"); System.out.println("3. Build LIR (Low-level IR)"); System.out.println("4. Linear scan register allocation"); System.out.println("5. Generate machine code"); System.out.println("6. Install compiled code"); } public void demonstrateOptimizations() { System.out.println("\nC1 Optimizations:"); System.out.println("- Method inlining (small methods)"); System.out.println("- Local value numbering"); System.out.println("- Null check elimination"); System.out.println("- Range check elimination"); System.out.println("- Simple loop optimizations"); } } // C2 Compiler Pipeline (Simplified) public static class C2Pipeline { public void compileMethod(byte[] bytecode) { System.out.println("C2 Compilation Pipeline:"); System.out.println("1. Parse bytecode and build Ideal IR"); System.out.println("2. Extensive global optimizations"); System.out.println("3. Multiple optimization phases"); System.out.println("4. Build Mach IR (Machine-specific)"); System.out.println("5. Graph-coloring register allocation"); System.out.println("6. Generate highly optimized machine code"); System.out.println("7. Install compiled code"); } public void demonstrateOptimizations() { System.out.println("\nC2 Advanced Optimizations:"); System.out.println("- Aggressive method inlining"); System.out.println("- Escape analysis"); System.out.println("- Lock coarsening/elimination"); System.out.println("- Loop unrolling"); System.out.println("- Vectorization (SIMD)"); System.out.println("- Dead code elimination"); System.out.println("- Global value numbering"); } } } } Performance Characteristics Comparison
package com.example.compiler; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** * Performance comparison between C1 and C2 compilation strategies */ public class CompilerPerformanceComparison { private static final int WARMUP_ITERATIONS = 10_000; private static final int MEASUREMENT_ITERATIONS = 100_000; /** * Methods that demonstrate different optimization behaviors */ public static class OptimizationExamples { // Method that benefits from C1's fast compilation public int simpleCalculation(int a, int b) { return (a * b) + (a / (b + 1)) - (a % (b + 2)); } // Method that benefits from C2's advanced optimizations public long complexLoopOptimization(int[] array) { long sum = 0; // This loop can be vectorized by C2 for (int i = 0; i < array.length; i++) { sum += array[i] * array[i]; } return sum; } // Method with escape analysis opportunities public String escapeAnalysisExample(int x, int y) { // C2 can eliminate this object allocation through escape analysis Point point = new Point(x, y); return point.toString(); } // Method demonstrating lock optimizations private final Object lock = new Object(); private int counter = 0; public void lockOptimizationExample() { // C2 can perform lock coarsening or elimination synchronized (lock) { counter++; } } // Inner class for escape analysis demonstration private static class Point { private final int x; private final int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "Point(" + x + ", " + y + ")"; } } } /** * Benchmark to compare C1 vs C2 performance characteristics */ public static class CompilerBenchmark { private final OptimizationExamples examples = new OptimizationExamples(); public void runBenchmark() { System.out.println("=== C1 vs C2 Compiler Benchmark ==="); // Warm up both compilers System.out.println("Warming up..."); warmup(); // Benchmark simple calculations (C1 friendly) benchmarkSimpleCalculations(); // Benchmark complex optimizations (C2 friendly) benchmarkComplexOptimizations(); // Benchmark escape analysis benchmarkEscapeAnalysis(); // Benchmark lock optimizations benchmarkLockOptimizations(); } private void warmup() { for (int i = 0; i < WARMUP_ITERATIONS; i++) { examples.simpleCalculation(i, i + 1); examples.complexLoopOptimization(new int[]{1, 2, 3, 4, 5}); examples.escapeAnalysisExample(i, i * 2); examples.lockOptimizationExample(); } } private void benchmarkSimpleCalculations() { System.out.println("\n1. Simple Calculations (C1-friendly):"); long startTime = System.nanoTime(); int result = 0; for (int i = 0; i < MEASUREMENT_ITERATIONS; i++) { result += examples.simpleCalculation(i, i + 1); } long duration = System.nanoTime() - startTime; System.out.printf("Result: %,d, Time: %,d ns, Throughput: %,d ops/ms%n", result, duration, (MEASUREMENT_ITERATIONS * 1_000_000L) / duration); } private void benchmarkComplexOptimizations() { System.out.println("\n2. Complex Loop Optimizations (C2-friendly):"); int[] array = new int[1000]; for (int i = 0; i < array.length; i++) { array[i] = i; } long startTime = System.nanoTime(); long result = 0; for (int i = 0; i < MEASUREMENT_ITERATIONS / 100; i++) { result += examples.complexLoopOptimization(array); } long duration = System.nanoTime() - startTime; System.out.printf("Result: %,d, Time: %,d ns, Throughput: %,d ops/ms%n", result, duration, (MEASUREMENT_ITERATIONS * 1_000_000L) / (duration * 100)); } private void benchmarkEscapeAnalysis() { System.out.println("\n3. Escape Analysis (C2-only optimization):"); long startTime = System.nanoTime(); for (int i = 0; i < MEASUREMENT_ITERATIONS; i++) { examples.escapeAnalysisExample(i, i * 2); } long duration = System.nanoTime() - startTime; System.out.printf("Time: %,d ns, Throughput: %,d ops/ms%n", duration, (MEASUREMENT_ITERATIONS * 1_000_000L) / duration); // Note: C1 cannot eliminate the object allocation System.out.println("C2 can eliminate object allocation via escape analysis"); } private void benchmarkLockOptimizations() { System.out.println("\n4. Lock Optimizations (C2 advantage):"); long startTime = System.nanoTime(); for (int i = 0; i < MEASUREMENT_ITERATIONS; i++) { examples.lockOptimizationExample(); } long duration = System.nanoTime() - startTime; System.out.printf("Time: %,d ns, Throughput: %,d ops/ms%n", duration, (MEASUREMENT_ITERATIONS * 1_000_000L) / duration); System.out.println("C2 can perform lock coarsening or elimination"); } } } Tiered Compilation in Action
package com.example.compiler; import java.lang.management.CompilerMXBean; import java.lang.management.ManagementFactory; import java.util.concurrent.atomic.AtomicInteger; /** * Demonstrates tiered compilation behavior and compiler transitions */ public class TieredCompilationDemo { private static final AtomicInteger methodInvocationCount = new AtomicInteger(); /** * Methods that trigger different compilation levels */ public static class TieredMethods { // Level 1: Interpreted execution public void interpretedMethod() { methodInvocationCount.incrementAndGet(); // Simple work to keep method alive Math.sqrt(methodInvocationCount.get()); } // Level 2: C1 compilation with profiling public void c1CompiledMethod() { methodInvocationCount.incrementAndGet(); // More complex work to trigger C1 compilation double result = 0; for (int i = 0; i < 100; i++) { result += Math.pow(i, 2); } } // Level 3: C1 compilation with full optimizations public void c1OptimizedMethod() { methodInvocationCount.incrementAndGet(); // Even more work to trigger full C1 optimizations long sum = 0; for (int i = 0; i < 1000; i++) { sum += i * i; if (sum % 2 == 0) { sum -= i; } } } // Level 4: C2 compilation (server compiler) public void c2CompiledMethod() { methodInvocationCount.incrementAndGet(); // Complex work that benefits from C2 optimizations int[] array = new int[1000]; for (int i = 0; i < array.length; i++) { array[i] = i; } // This loop can be vectorized by C2 long total = 0; for (int value : array) { total += value * value * value; } // String operations that benefit from C2 optimizations StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) { sb.append(i).append(","); } } // Method that becomes hot and triggers OSR (On-Stack Replacement) public void onStackReplacementMethod() { methodInvocationCount.incrementAndGet(); // Long-running loop that triggers OSR long result = 0; for (int i = 0; i < 1_000_000; i++) { result += i * Math.log(i + 1); if (i % 1000 == 0) { // Prevent complete dead code elimination Math.sqrt(result); } } } } /** * Monitors compilation events and tier transitions */ public static class CompilationMonitor { private final CompilerMXBean compilerBean = ManagementFactory.getCompilerMXBean(); public void printCompilationInfo() { if (compilerBean.isCompilationTimeMonitoringSupported()) { System.out.println("Compilation Time Monitoring: Supported"); System.out.printf("Total Compilation Time: %,d ms%n", compilerBean.getTotalCompilationTime()); } else { System.out.println("Compilation Time Monitoring: Not Supported"); } System.out.printf("Method Invocation Count: %,d%n", methodInvocationCount.get()); } public void demonstrateTierTransitions() { TieredMethods methods = new TieredMethods(); System.out.println("=== Tiered Compilation Demonstration ==="); // Phase 1: Interpreted execution System.out.println("\nPhase 1: Interpreted Execution"); for (int i = 0; i < 1_000; i++) { methods.interpretedMethod(); } printCompilationInfo(); // Phase 2: Trigger C1 compilation System.out.println("\nPhase 2: C1 Compilation"); for (int i = 0; i < 10_000; i++) { methods.c1CompiledMethod(); } printCompilationInfo(); // Phase 3: Trigger C1 with full optimizations System.out.println("\nPhase 3: C1 with Full Optimizations"); for (int i = 0; i < 50_000; i++) { methods.c1OptimizedMethod(); } printCompilationInfo(); // Phase 4: Trigger C2 compilation System.out.println("\nPhase 4: C2 Compilation"); for (int i = 0; i < 100_000; i++) { methods.c2CompiledMethod(); } printCompilationInfo(); // Phase 5: Demonstrate OSR System.out.println("\nPhase 5: On-Stack Replacement"); for (int i = 0; i < 10; i++) { methods.onStackReplacementMethod(); } printCompilationInfo(); } } /** * JVM flag recommendations for different use cases */ public static class CompilerFlags { public static void printClientCompilerFlags() { System.out.println("\n=== C1 (Client) Compiler Flags ==="); System.out.println("-client : Use client VM (C1 compiler)"); System.out.println("-XX:TieredStopAtLevel=1 : Stop at C1 compilation"); System.out.println("-XX:+TieredCompilation : Enable tiered compilation"); System.out.println("-XX:CompileThreshold=1000 : Early compilation trigger"); System.out.println("-XX:+PrintCompilation : Print compilation events"); System.out.println("-XX:+PrintInlining : Print method inlining decisions"); } public static void printServerCompilerFlags() { System.out.println("\n=== C2 (Server) Compiler Flags ==="); System.out.println("-server : Use server VM (C2 compiler)"); System.out.println("-XX:TieredStopAtLevel=4 : Enable full C2 compilation"); System.out.println("-XX:CompileThreshold=10000 : Higher threshold for C2"); System.out.println("-XX:+AggressiveOpts : Enable aggressive optimizations"); System.out.println("-XX:+DoEscapeAnalysis : Enable escape analysis"); System.out.println("-XX:+OptimizeStringConcat : Optimize string concatenation"); } public static void printAdvancedOptimizationFlags() { System.out.println("\n=== Advanced C2 Optimization Flags ==="); System.out.println("-XX:+UnlockExperimentalVMOptions : Enable experimental features"); System.out.println("-XX:+UseSuperWord : Enable vectorization (SIMD)"); System.out.println("-XX:+AlignVector : Align vector operations"); System.out.println("-XX:+UseVectorCmov : Use vector conditional moves"); System.out.println("-XX:+UseCMoveUnconditionally : Use conditional moves"); System.out.println("-XX:+EliminateAutoBox : Eliminate autoboxing"); System.out.println("-XX:+OptimizeFill : Optimize array fill operations"); } public static void printDiagnosticFlags() { System.out.println("\n=== Compiler Diagnostic Flags ==="); System.out.println("-XX:+PrintCompilation : Print method compilation"); System.out.println("-XX:+PrintInlining : Print inlining decisions"); System.out.println("-XX:+PrintAssembly : Print generated assembly (requires hsdis)"); System.out.println("-XX:+PrintNMethods : Print native method info"); System.out.println("-XX:+PrintCodeCache : Print code cache usage"); System.out.println("-XX:+LogCompilation : Log compilation to file"); System.out.println("-XX:LogFile=compilation.log : Specify compilation log file"); } } } Optimization Techniques Comparison
package com.example.compiler; import java.util.Arrays; import java.util.Random; /** * Demonstrates specific optimization differences between C1 and C2 */ public class OptimizationComparison { private static final Random random = new Random(); private static final int ARRAY_SIZE = 10_000; /** * Examples showing different optimization capabilities */ public static class OptimizationExamples { // 1. Loop Optimizations public long loopOptimizations(int[] array) { long sum = 0; // C2 can unroll this loop and potentially vectorize it for (int i = 0; i < array.length; i++) { sum += array[i]; } return sum; } // 2. Method Inlining public int methodInliningExample(int a, int b) { // Small methods are inlined by both C1 and C2 return add(multiply(a, b), subtract(a, b)); } private int add(int a, int b) { return a + b; } private int multiply(int a, int b) { return a * b; } private int subtract(int a, int b) { return a - b; } // 3. Escape Analysis (C2 only) public String escapeAnalysisExample() { // C2 can allocate this on stack instead of heap StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) { sb.append(i); } return sb.toString(); } // 4. Lock Coarsening (C2 advantage) private final Object lock = new Object(); private int counter = 0; public void lockCoarseningExample() { // C2 can merge these synchronized blocks synchronized (lock) { counter++; } synchronized (lock) { counter--; } synchronized (lock) { counter *= 2; } } // 5. Dead Code Elimination public int deadCodeElimination(boolean flag) { int result = 0; // This branch can be eliminated if flag is constant if (flag) { result = computeExpensiveValue(); } else { result = 42; } // This calculation might be eliminated if result is unused int unused = result * 2; return result; } private int computeExpensiveValue() { // Simulate expensive computation int sum = 0; for (int i = 0; i < 1000; i++) { sum += i * i; } return sum; } // 6. Range Check Elimination public int rangeCheckElimination(int[] array, int index) { // C2 can eliminate some range checks if (index >= 0 && index < array.length) { return array[index]; } return -1; } // 7. Vectorization (SIMD - C2 advanced optimization) public void vectorizationExample(float[] a, float[] b, float[] result) { // C2 can use SIMD instructions for this loop for (int i = 0; i < a.length; i++) { result[i] = a[i] + b[i]; } } // 8. Type Sharpening public String typeSharpeningExample(Object obj) { // C2 can optimize based on actual type if (obj instanceof String) { return ((String) obj).toUpperCase(); } return "unknown"; } } /** * Benchmark to measure optimization effectiveness */ public static class OptimizationBenchmark { private final OptimizationExamples examples = new OptimizationExamples(); public void runOptimizationBenchmark() { System.out.println("=== C1 vs C2 Optimization Effectiveness ==="); // Setup test data int[] array = new int[ARRAY_SIZE]; Arrays.fill(array, 1); float[] floatArrayA = new float[ARRAY_SIZE]; float[] floatArrayB = new float[ARRAY_SIZE]; float[] floatResult = new float[ARRAY_SIZE]; Arrays.fill(floatArrayA, 1.5f); Arrays.fill(floatArrayB, 2.5f); // Warm up warmup(array, floatArrayA, floatArrayB, floatResult); // Benchmark each optimization benchmarkLoopOptimizations(array); benchmarkMethodInlining(); benchmarkEscapeAnalysis(); benchmarkVectorization(floatArrayA, floatArrayB, floatResult); benchmarkTypeSharpening(); } private void warmup(int[] array, float[] a, float[] b, float[] result) { for (int i = 0; i < 1000; i++) { examples.loopOptimizations(array); examples.methodInliningExample(i, i + 1); examples.escapeAnalysisExample(); examples.vectorizationExample(a, b, result); examples.typeSharpeningExample("test"); } } private void benchmarkLoopOptimizations(int[] array) { System.out.println("\n1. Loop Optimizations:"); long startTime = System.nanoTime(); long total = 0; for (int i = 0; i < 10_000; i++) { total += examples.loopOptimizations(array); } long duration = System.nanoTime() - startTime; System.out.printf("Total: %,d, Time: %,d ns%n", total, duration); System.out.println("C2 can vectorize and unroll loops more aggressively"); } private void benchmarkMethodInlining() { System.out.println("\n2. Method Inlining:"); long startTime = System.nanoTime(); int total = 0; for (int i = 0; i < 1_000_000; i++) { total += examples.methodInliningExample(i, i + 1); } long duration = System.nanoTime() - startTime; System.out.printf("Total: %,d, Time: %,d ns%n", total, duration); System.out.println("Both compilers inline, but C2 is more aggressive"); } private void benchmarkEscapeAnalysis() { System.out.println("\n3. Escape Analysis (C2 only):"); long startTime = System.nanoTime(); for (int i = 0; i < 100_000; i++) { examples.escapeAnalysisExample(); } long duration = System.nanoTime() - startTime; System.out.printf("Time: %,d ns%n", duration); System.out.println("C2 can eliminate object allocations via escape analysis"); } private void benchmarkVectorization(float[] a, float[] b, float[] result) { System.out.println("\n4. Vectorization (SIMD - C2 advanced):"); long startTime = System.nanoTime(); for (int i = 0; i < 10_000; i++) { examples.vectorizationExample(a, b, result); } long duration = System.nanoTime() - startTime; System.out.printf("Time: %,d ns%n", duration); System.out.println("C2 can use SIMD instructions for parallel operations"); } private void benchmarkTypeSharpening() { System.out.println("\n5. Type Sharpening:"); String testString = "Hello World"; long startTime = System.nanoTime(); String result = ""; for (int i = 0; i < 1_000_000; i++) { result = examples.typeSharpeningExample(testString); } long duration = System.nanoTime() - startTime; System.out.printf("Result: %s, Time: %,d ns%n", result, duration); System.out.println("C2 can optimize based on profiled type information"); } } } Compiler Selection Strategies
package com.example.compiler; import java.util.HashMap; import java.util.Map; /** * Strategies for choosing between C1 and C2 compilers */ public class CompilerSelectionStrategies { /** * Factors influencing compiler selection */ public static class CompilerSelectionFactors { public static boolean shouldUseC1(ApplicationProfile profile) { // Use C1 for applications with these characteristics: return profile.hasShortRuntime() || profile.isInteractiveApplication() || profile.hasLimitedMemory() || profile.requiresFastStartup(); } public static boolean shouldUseC2(ApplicationProfile profile) { // Use C2 for applications with these characteristics: return profile.hasLongRuntime() || profile.isServerApplication() || profile.hasHighThroughputRequirements() || profile.canTolerateSlowStartup(); } public static boolean shouldUseTieredCompilation(ApplicationProfile profile) { // Use tiered compilation for balanced requirements: return profile.requiresGoodStartup() && profile.requiresGoodPeakPerformance(); } } /** * Application profile for compiler selection */ public static class ApplicationProfile { private final Map<String, Object> characteristics = new HashMap<>(); public ApplicationProfile() { // Default characteristics characteristics.put("runtimeDuration", "medium"); characteristics.put("applicationType", "general"); characteristics.put("memoryConstraints", "none"); characteristics.put("startupRequirements", "moderate"); characteristics.put("performanceRequirements", "balanced"); } public ApplicationProfile setRuntimeDuration(String duration) { characteristics.put("runtimeDuration", duration); return this; } public ApplicationProfile setApplicationType(String type) { characteristics.put("applicationType", type); return this; } public ApplicationProfile setMemoryConstraints(String constraints) { characteristics.put("memoryConstraints", constraints); return this; } public ApplicationProfile setStartupRequirements(String requirements) { characteristics.put("startupRequirements", requirements); return this; } public ApplicationProfile setPerformanceRequirements(String requirements) { characteristics.put("performanceRequirements", requirements); return this; } // Query methods public boolean hasShortRuntime() { return "short".equals(characteristics.get("runtimeDuration")); } public boolean hasLongRuntime() { return "long".equals(characteristics.get("runtimeDuration")); } public boolean isInteractiveApplication() { return "interactive".equals(characteristics.get("applicationType")); } public boolean isServerApplication() { return "server".equals(characteristics.get("applicationType")); } public boolean hasLimitedMemory() { return "limited".equals(characteristics.get("memoryConstraints")); } public boolean requiresFastStartup() { return "fast".equals(characteristics.get("startupRequirements")); } public boolean canTolerateSlowStartup() { return "slow".equals(characteristics.get("startupRequirements")); } public boolean requiresGoodStartup() { String req = (String) characteristics.get("startupRequirements"); return "fast".equals(req) || "moderate".equals(req); } public boolean requiresGoodPeakPerformance() { String req = (String) characteristics.get("performanceRequirements"); return "high".equals(req) || "maximum".equals(req); } public boolean hasHighThroughputRequirements() { return "high".equals(characteristics.get("performanceRequirements")) || "maximum".equals(characteristics.get("performanceRequirements")); } } /** * JVM flag configuration based on application profile */ public static class JVMConfiguration { public static String[] getFlagsForProfile(ApplicationProfile profile) { if (CompilerSelectionFactors.shouldUseC1(profile)) { return getC1OptimizedFlags(); } else if (CompilerSelectionFactors.shouldUseC2(profile)) { return getC2OptimizedFlags(); } else { return getTieredCompilationFlags(); } } private static String[] getC1OptimizedFlags() { return new String[] { "-client", "-XX:TieredStopAtLevel=1", "-XX:CompileThreshold=1000", "-Xms64m", "-Xmx256m" }; } private static String[] getC2OptimizedFlags() { return new String[] { "-server", "-XX:-TieredCompilation", // Disable tiered compilation "-XX:CompileThreshold=10000", "-Xms512m", "-Xmx2g", "-XX:+AggressiveOpts", "-XX:+UseParallelGC" }; } private static String[] getTieredCompilationFlags() { return new String[] { "-server", // Default in modern JDKs "-XX:+TieredCompilation", "-XX:CompileThreshold=1500", "-XX:Tier3CompileThreshold=10000", "-XX:Tier4CompileThreshold=20000", "-Xms256m", "-Xmx1g" }; } public static void printRecommendedConfiguration(ApplicationProfile profile) { String[] flags = getFlagsForProfile(profile); System.out.println("=== Recommended JVM Configuration ==="); System.out.println("Application Profile: " + profile.characteristics); System.out.println("Recommended Flags:"); for (String flag : flags) { System.out.println(" " + flag); } } } /** * Use case examples with recommended configurations */ public static class UseCaseExamples { public static void demonstrateUseCases() { System.out.println("=== Compiler Selection Use Cases ==="); // Use Case 1: Desktop GUI Application ApplicationProfile desktopApp = new ApplicationProfile() .setApplicationType("interactive") .setRuntimeDuration("medium") .setStartupRequirements("fast") .setPerformanceRequirements("moderate"); System.out.println("\n1. Desktop GUI Application:"); JVMConfiguration.printRecommendedConfiguration(desktopApp); // Use Case 2: Long-running Server Application ApplicationProfile serverApp = new ApplicationProfile() .setApplicationType("server") .setRuntimeDuration("long") .setStartupRequirements("slow") .setPerformanceRequirements("maximum"); System.out.println("\n2. Server Application:"); JVMConfiguration.printRecommendedConfiguration(serverApp); // Use Case 3: Mobile Application ApplicationProfile mobileApp = new ApplicationProfile() .setApplicationType("interactive") .setRuntimeDuration("short") .setMemoryConstraints("limited") .setStartupRequirements("fast") .setPerformanceRequirements("moderate"); System.out.println("\n3. Mobile Application:"); JVMConfiguration.printRecommendedConfiguration(mobileApp); // Use Case 4: Batch Processing ApplicationProfile batchApp = new ApplicationProfile() .setApplicationType("batch") .setRuntimeDuration("long") .setStartupRequirements("moderate") .setPerformanceRequirements("high"); System.out.println("\n4. Batch Processing Application:"); JVMConfiguration.printRecommendedConfiguration(batchApp); } } } Monitoring and Diagnostics
package com.example.compiler; import java.lang.management.CompilationMXBean; import java.lang.management.ManagementFactory; import java.util.concurrent.atomic.AtomicLong; /** * Monitoring and diagnostics for compiler behavior */ public class CompilerMonitoring { private static final AtomicLong compiledMethodCount = new AtomicLong(); private static final AtomicLong compilationTime = new AtomicLong(); /** * Compiler monitoring utilities */ public static class CompilerMonitor { private final CompilationMXBean compilationBean; public CompilerMonitor() { this.compilationBean = ManagementFactory.getCompilationMXBean(); } public void printCompilerInfo() { System.out.println("=== Compiler Information ==="); System.out.println("Compiler Name: " + compilationBean.getName()); System.out.println("JIT Compiler: " + (compilationBean.isCompilationTimeMonitoringSupported() ? "Supported" : "Not Supported")); if (compilationBean.isCompilationTimeMonitoringSupported()) { System.out.printf("Total Compilation Time: %,d ms%n", compilationBean.getTotalCompilationTime()); } } public void monitorCompilationActivity() { new Thread(() -> { long lastCompilationTime = compilationBean.getTotalCompilationTime(); long lastMethodCount = compiledMethodCount.get(); while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(5000); // Check every 5 seconds long currentCompilationTime = compilationBean.getTotalCompilationTime(); long currentMethodCount = compiledMethodCount.get(); long timeDelta = currentCompilationTime - lastCompilationTime; long methodDelta = currentMethodCount - lastMethodCount; if (timeDelta > 0 || methodDelta > 0) { System.out.printf("Compilation Activity: %,d methods compiled, %,d ms spent%n", methodDelta, timeDelta); } lastCompilationTime = currentCompilationTime; lastMethodCount = currentMethodCount; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }, "CompilerMonitor").start(); } } /** * Methods to trigger and observe compilation */ public static class CompilationTrigger { public void triggerC1Compilation() { // Methods that will be compiled by C1 for (int i = 0; i < 10_000; i++) { simpleMethod(i); } } public void triggerC2Compilation() { // Methods that will be compiled by C2 after becoming hot for (int i = 0; i < 100_000; i++) { complexMethod(i); } } private int simpleMethod(int x) { compiledMethodCount.incrementAndGet(); return x * 2 + 1; } private long complexMethod(int x) { compiledMethodCount.incrementAndGet(); long result = 0; for (int i = 0; i < 1000; i++) { result += Math.pow(x, i % 10); } return result; } } /** * Diagnostic information about current compilation state */ public static class CompilationDiagnostics { public static void printSystemProperties() { System.out.println("\n=== Compiler-related System Properties ==="); printProperty("java.vm.name"); printProperty("java.vm.version"); printProperty("java.vm.info"); printProperty("java.compiler"); printProperty("jdk.debug"); } public static void printCompilerFlags() { System.out.println("\n=== Effective Compiler Flags ==="); // These would be parsed from RuntimeMXBean in real implementation System.out.println("(Run with -XX:+PrintFlagsFinal to see all flags)"); } private static void printProperty(String key) { String value = System.getProperty(key); if (value != null) { System.out.printf("%s: %s%n", key, value); } } } } Best Practices and Recommendations
```java
package com.example.compiler;
/**
- Best practices for working with C1 and C2 compilers
*/
public class CompilerBestPractices { /**- Code patterns that work well with both compilers
*/
public static class OptimizedCodePatterns { // 1
- Code patterns that work well with both compilers