JVM & Memory

101. Java Flight Recorder (JFR) & Low-Overhead Production Profiling

Java Flight Recorder (JFR) is an always-on, low-overhead (<1% CPU) event tracing and profiling framework integrated into the JVM kernel, paired with JDK Mission Control (JMC) for diagnostics.

Java 21+ (Built into OpenJDK)

Explanation

Traditional profilers often attach via JVM TI agents or sampling threads that inject significant overhead (10โ€“30%), distorting benchmark results and making continuous production profiling risky. Java Flight Recorder (JFR) is integrated directly into the HotSpot runtime engine. It writes binary event buffers with under 1% overhead, making it safe to run 24/7 in high-throughput production environments.

JFR captures fine-grained events: CPU sampling, memory allocation rates, garbage collection pauses, thread locks/contention, I/O latency (file and socket), class loading, and virtual thread pinning events (jdk.VirtualThreadPinned). Events are recorded into rotating in-memory circular buffers or dumped to .jfr files on trigger conditions.

Developers can also define custom application events by subclassing jdk.jfr.Event. These custom business events (e.g., checkout latency, DB query duration) are correlated with underlying JVM metrics (GC spikes, lock contention) inside analysis tools like JDK Mission Control (JMC) or exported to Prometheus/Grafana.

Example

import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;

public class JfrCustomEventDemo {

    // Define a custom production JFR event
    @Name("com.example.OrderProcessing")
    @Label("Order Processing Event")
    @Category({"Business", "Orders"})
    @Description("Measures time spent validating and processing customer orders")
    static class OrderEvent extends Event {
        @Label("Order ID")
        private String orderId;

        @Label("Total Amount")
        private double amount;

        public void setOrderId(String id) { this.orderId = id; }
        public void setAmount(double amt) { this.amount = amt; }
    }

    public static void processOrder(String id, double amount) {
        OrderEvent event = new OrderEvent();
        event.setOrderId(id);
        event.setAmount(amount);

        event.begin(); // Mark start time
        try {
            // Simulated business logic
            Thread.sleep(15);
        } catch (InterruptedException ignored) {
        } finally {
            event.commit(); // Writes event if enabled by active JFR profile
        }
    }

    public static void main(String[] args) {
        System.out.println("Processing sample orders with JFR event emission...");
        processOrder("ORD-1001", 149.99);
        System.out.println("Done. Run with: -XX:StartFlightRecording=filename=app.jfr,dumponexit=true");
    }
}

Sources