Back to Java 11 Features
Q4Question 4 of 5

What is Java Flight Recorder?

Key Concepts
  • JFR is a built-in JVM profiler with approximately 1-2% overhead, safe for production use
  • Records GC pauses, memory allocations, thread contention, CPU hotspots, I/O latency, and class loading
  • Start with -XX:StartFlightRecording=duration=60s,filename=app.jfr or programmatically with jcmd
  • Analyze recordings with JDK Mission Control (JMC) or the jfr command-line tool
  • Custom application events can be created by extending jdk.jfr.Event
  • Free and open-sourced since Java 11 (was commercial-only in Oracle JDK 8)

Definition

Java Flight Recorder is a low-overhead profiling framework built into the JVM that continuously records GC, allocation, thread, and CPU events for production analysis.
  • JFR (Java Flight Recorder) is a profiling and diagnostics framework built into the JVM since Java 11 (free).
  • Low overhead: approximately 1-2% performance impact, designed for always-on production monitoring.
  • Records: GC pauses, memory allocations, thread contention, CPU hotspots, I/O latency, class loading, and exceptions.
  • Start recording: command-line flag -XX:StartFlightRecording=duration=60s,filename=app.jfr or at runtime with jcmd JFR.start.
  • Analyze: open the .jfr file in JDK Mission Control (JMC) or use the jfr command-line tool.
  • Custom events: extend jdk.jfr.Event to record domain-specific events like settlement batch timing.

JFR is like the bank's security camera system that records everything: customer flow, employee activity, system access. It runs continuously with minimal impact on daily operations. When something goes wrong (a performance incident), you review the recording to find the cause. Unlike security cameras, JFR costs almost nothing in resources.

Understanding the Concepts

What does JFR record?

JFR continuously records JVM events into a compact binary .jfr file. The events include:

  • GC events: pause times, heap sizes before and after, GC algorithm details.
  • Memory allocation: which threads allocated the most memory, allocation rates.
  • Thread contention: lock wait times, thread states, blocked threads.
  • CPU profiling: method sampling to identify hot code paths.
  • I/O latency: file and socket read/write durations.
  • Exceptions: every exception thrown, even if caught.

How do you start a recording?

BASH
# Start with the application
java -XX:StartFlightRecording=duration=60s,filename=app.jfr \
     -jar banking-service.jar

# Start on a running process
jcmd <pid> JFR.start duration=60s filename=settlement.jfr

# Stop a running recording
jcmd <pid> JFR.stop name=1

How do you create custom application events?

JAVA
package com.bank.monitoring;

import jdk.jfr.*;

@Name("com.bank.SettlementBatch")
@Label("Settlement Batch")
@Description("Records settlement batch execution")
public class SettlementEvent extends Event {
    @Label("Batch ID")
    String batchId;

    @Label("Transaction Count")
    int transactionCount;

    @Label("Total Amount")
    long totalAmountPaise;
}

// Usage:
SettlementEvent event = new SettlementEvent();
event.batchId = "BATCH-20240115";
event.transactionCount = 1500;
event.totalAmountPaise = 75000000L;
event.begin();
// ... execute batch ...
event.commit();  // records duration automatically

How do you analyze recordings?

Use JDK Mission Control (JMC) for visual analysis or the jfr command-line tool.

BASH
# Print summary of events
jfr summary app.jfr

# Print specific event type
jfr print --events jdk.GarbageCollection app.jfr

# Print custom events
jfr print --events com.bank.SettlementBatch app.jfr

How is JFR different from traditional profiling?

| Feature | JFR | Traditional Profiler |
|---------|-----|---------------------|
| Overhead | ~1-2% | 5-50% |
| Production safe | Yes | Usually not |
| Always-on | Designed for it | Attach-on-demand |
| Built-in | Part of JDK | External tool |
| Custom events | Yes (extend Event) | Varies |

What about JFR Streaming API (Java 14+)?

JFR data can be streamed in real-time for continuous monitoring dashboards.

JAVA
import jdk.jfr.consumer.RecordingStream;

try (var stream = new RecordingStream()) {
    stream.enable("jdk.GarbageCollection").withThreshold(java.time.Duration.ofMillis(100));
    stream.onEvent("jdk.GarbageCollection", event -> {
        System.out.println("GC pause: " + event.getDuration().toMillis() + "ms");
    });
    stream.startAsync(); // runs in background
}

What are common mistakes?

JAVA
// WRONG: leaving JFR recordings running indefinitely without a duration limit
java -XX:StartFlightRecording=filename=app.jfr -jar banking-service.jar
// The .jfr file grows unbounded!

// CORRECT: set a duration or maxSize
java -XX:StartFlightRecording=duration=60s,filename=app.jfr -jar banking-service.jar
java -XX:StartFlightRecording=maxsize=500m,filename=app.jfr -jar banking-service.jar

What should a senior engineer know?

  • JFR complements metrics and traces: metrics tell you SOMETHING is slow, JFR tells you WHY at the JVM/allocation/lock level.
  • The programmatic API (jdk.jfr.Recording) lets you start and stop recordings in integration tests to capture performance baselines.
  • JFR data can be streamed in real-time with the JFR Streaming API (Java 14+) for continuous monitoring dashboards.
  • In banking, JFR recording of GC pauses during peak trading hours helps tune GC settings for latency-sensitive services.

Visual Overview

DIAGRAM
  ┌───────────────────────────────────────┐
  │          Java Application             │
  │                                       │
  │  ┌─────────────────────────────────┐  │
  │  │   JFR (always-on, ~1% overhead) │  │
  │  │                                 │  │
  │  │  Records:                       │  │
  │  │  ├── GC pauses                  │  │
  │  │  ├── Memory allocations         │  │
  │  │  ├── Thread contention          │  │
  │  │  ├── CPU hotspots               │  │
  │  │  ├── I/O latency                │  │
  │  │  └── Custom events              │  │
  │  └──────────────┬──────────────────┘  │
  └─────────────────┼─────────────────────┘
                    │
                    ▼
              app.jfr file
                    │
                    ▼
          JDK Mission Control (JMC)

Key Takeaway

Java Flight Recorder is a production-safe profiling tool built into the JVM since Java 11. It records GC pauses, memory allocations, thread contention, CPU hotspots, and I/O latency with approximately 1-2% overhead, making it safe for always-on monitoring.

Start recording with -XX:StartFlightRecording on the command line or jcmd on a running process. Analyze the .jfr file with JDK Mission Control for visual analysis. Create custom application events by extending jdk.jfr.Event to record domain-specific metrics like settlement batch timing.

At National Bank of India, the settlement service enables JFR during peak hours to capture GC pauses and lock contention. Mission Control reveals that a BigDecimal allocation hotspot causes 200ms GC pauses, guiding optimization.

Remember one sentence: JFR is the built-in, always-on, low-overhead profiler that tells you WHY your application is slow in production.

---

Share
Use ← → arrow keys to navigate