Java Concurrency & Async Programming · Lesson 22

JVM JIT, Code Cache, and Warmup Diagnosis

Diagnose Java 25 tiered compilation, compilation queues, deoptimization, code cache pressure, warmup, JFR, and AOT profile boundaries.

Quick answer

HotSpot begins with interpreted and lower-tier execution, profiles observed behavior, compiles hot methods, and can later deoptimize assumptions. Diagnose this lifecycle with startup and steady-state latency, compiler CPU, compilation queues, JFR events, unified compilation logs, deoptimization evidence, and code cache occupancy. Warmup is workload-specific; sleeping for a fixed time or sending unrepresentative synthetic traffic does not prove readiness.

Java 25 adds ahead-of-time cache and method-profile capabilities that can shorten startup and warmup for matching workloads. They do not freeze optimization or replace production profiling. JFR CPU-time profiling in JDK 25 is experimental and Linux-specific in its initial delivery, so isolate it from the stable diagnostic baseline and check lost-sample evidence.

Learning objectives

  • Explain how tiered compilation, profiling, deoptimization, the compiler queue, and code cache affect startup and steady-state service behavior.
  • Evaluate Java 25 JFR and AOT evidence without treating a training run or sampled profile as representative production proof.

Prerequisites

Read JVM Thread Dumps, Safepoints, and CPU Saturation and JVM Profiling and JFR before attributing CPU or latency to compilation.

Evidence and system boundary

Tiered compilation balances fast startup and optimized steady-state code. Profiles record observed method and type behavior; compilers use those observations to optimize hot paths. If assumptions become invalid, compiled code can be deoptimized and execution can return to a lower tier. The code cache holds generated native code and has distinct profiled, non-profiled, and non-method areas under the default segmented configuration.

These are explanatory Java 25 observations, not a flag set executed or recommended for production:

jcmd <pid> Compiler.queue
jcmd <pid> Compiler.codecache
jcmd <pid> Compiler.CodeHeap_Analytics
java -Xlog:jit+compilation=debug,codecache=debug -jar order-service.jar

The jcmd specification assigns impact to commands. Compilation logging can be verbose and change timing. Bound capture and preserve runtime, CPU limits, uptime, workload, service version, and warmup stage.

Diagnose warmup and compilation

Separate cold start, application initialization, class loading and linking, dependency establishment, cache population, JIT compilation, and actual business readiness. A health endpoint can become ready before common checkout paths are compiled or downstream pools are warm. Conversely, deliberately delaying readiness can waste capacity and conceal dependency failures.

Inspect compiler queue length and compiler-thread CPU when latency rises after a rollout. A queue is not automatically a problem; it shows pending compilation at that moment. Correlate it with request shapes, JFR compilation and execution events, code cache, deoptimization, container throttling, and latency. A burst on fresh replicas may be expected, while repeated steady-state compilation can indicate changing workload or code generation.

Code cache pressure can disable or disrupt expected compilation behavior. Use Compiler.codecache, Compiler.CodeHeap_Analytics, and -Xlog:codecache to test that hypothesis. Do not increase reserved code cache solely because one area looks full; confirm compilation consequences, process memory budget, and why the application creates that volume of generated code.

Java 25 AOT caches can preserve class-loading, linking, and method-profile information from a training run. The training workload must represent intended production paths without embedding credentials or environment-specific state. Production continues profiling because real behavior can diverge. Treat cache generation as a versioned build artifact with provenance and compatibility checks.

JFR CPU-time profiling is experimental in Java 25. It measures CPU-time samples for Java execution on supported Linux configurations and emits lost-sample evidence. Keep stable wall-clock and execution-sampling methods available, and do not compare sample counts across configurations as if they were request populations.

Production failure scenario

A Spring order service scales from two to twenty replicas. New replicas pass readiness quickly, but p99 rises for several minutes while compiler CPU and queue depth spike under throttled CPU. Code cache remains healthy and the service settles after common paths compile.

The team tests a representative canary warmup and an approved Java 25 AOT artifact tied to the exact build. It also reserves startup CPU and limits rollout concurrency. Recovery is verified through fresh checkout latency, errors, compiler CPU, queue depth, dependency capacity, and durable orders. One faster startup benchmark does not establish production capacity.

Common misconceptions

  • Warmup is not a fixed number of seconds independent of workload and CPU.
  • A nonempty compiler queue does not prove the compiler caused user latency.
  • More code cache cannot repair excessive dynamic code generation or unrelated CPU throttling.
  • An AOT training run does not lock production behavior or eliminate runtime profiling.
  • JFR CPU-time samples are not complete request counts, and the Java 25 feature is experimental.

Decision checklist

  • Separate startup, initialization, dependency warmup, JIT warmup, and business readiness.
  • Record JDK update, flags, CPU limits, uptime, version, and request shape.
  • Correlate compiler CPU and queue evidence with latency and throttling.
  • Inspect code cache consequences before changing its size.
  • Version AOT artifacts with the application and representative training contract.
  • Label experimental JFR events and inspect lost samples.
  • Canary startup and rollout policy changes with a rollback path.
  • Verify steady-state user outcomes and durable orders, not startup speed alone.

Complete the sequence with Evidence-Based JVM Tuning and Capacity Verification. The broader signal model lives in Production Observability & SRE, while the canonical sequence remains the Java Concurrency course and topic cluster.

Official sources

Official sources accessed August 19, 2026. Recheck AOT compatibility, logging tags, experimental JFR status, and command impact for the exact Java 25 update.

Knowledge check

Check your understanding

Answer both questions correctly to mark this lesson as mastered. You can retry without penalty.

1. New replicas show compiler CPU and queue growth under throttled startup CPU, then stabilize; what should the rollout test?

2. What can a Java 25 AOT training run establish?