How Java Flight Recorder WorksHow Java Flight Recorder WorksStage 1 of 7 · 7 stages · ~7 min
JAVA RUNTIME · BUILT-IN PROFILER

Watch a busy JVM record itself without getting in the way

Follow one computed trace from an event gate to private buffers, periodic stack samples, compact references, and a rolling JFR recording.

7 stages~7 min
  1. FILTER EVENTS
  2. BUFFER + SAMPLE
  3. KEEP RECENT HISTORY
Read mode · answer first

How Java Flight Recorder records JVM profiles with low overhead

See how JFR filters typed events, writes private buffers, samples stacks, reuses metadata, and preserves recent history in recording chunks.

Cheat sheet · 5 essential ideas

The whole story in 5 lines

JFR stays light by filtering early, writing privately, sampling sparsely, reusing metadata, and rotating complete chunks.

  1. Settings reject unneeded events before their data enters the recording path.
  2. Private write lanes let application threads append without sharing one hot cursor.
  3. Periodic snapshots trade perfect detail for a useful profile with bounded work.
  4. Shared IDs keep repeated stacks and methods from bloating every event record.
  5. Self-contained chunks turn compact records into a recoverable rolling history.
How does JFR avoid recording every duration event?
Enabled settings and thresholds reject unneeded duration events before their details reach the recording path.
Why do application threads not share one hot JFR append cursor?
Each application thread appends into a private buffer and hands off the full buffer to shared memory.
How can periodic samples reveal hot code?
Repeated snapshots land most often in methods that occupy more execution time, so their profile counts grow larger.
Why do sample events carry stack IDs?
JFR stores repeated stack and method structures once, then lets many events refer to them with compact IDs.
How does a continuous recording keep recent history parseable?
Each chunk carries the metadata and checkpoints needed for parsing, while retention removes the oldest complete chunks.
Download PDF cheat sheet
Stage 1 of 7

Meet the pieces JFR moves

Meet the pieces JFR moves

Java Flight Recorder watches a running JVM through small typed records. Let us meet the pieces before following their journey.

An event is one timestamped fact, such as a long lock wait, and its type tells tools which fields belong inside it.

A threshold is an early gate that rejects short duration events, which avoids paying to record details that the current configuration does not need.

A thread-local buffer is a private strip of memory. One Java thread appends event bytes using its own write cursor.

A stack sample is a periodic snapshot of where a thread is executing, so repeated snapshots can reveal which methods stay busy.

A reference pool stores repeated stacks and method metadata once. Those compact records will later need a durable container.

A chunk bundles the event stream with the information needed to parse it, while a rolling recording can discard older chunks as limits are reached.

These six pieces form one low-overhead path, so let us begin with the gate that decides whether an event enters at all.

Stage 2 of 7

Useful events pass a cheap gate

Useful events pass a cheap gate

Now that we know the cast, we can follow three illustrative duration events. A setting decides whether each one is worth recording.

The enabled setting is the first check, because a disabled event type can stop before JFR gathers or writes its optional details.

The threshold then compares each event duration with the configured minimum, which keeps short events outside the buffer path.

The active threshold is 5 milliseconds, and the three events last 2, 9, and 28 milliseconds. Which records will cross the gate?

Pause and predict
Which duration events pass the 5 ms threshold?

The accepted records move into a compact stream while the shorter record falls away, making the result of the gate visible before any buffer work begins.

Switch the Threshold control through every option. Compare which duration markers enter the recording and which disappear before buffer work.

Early filtering protects the rest of the recording path from avoidable work. Next, each accepted record needs a low-contention place to land.

Stage 3 of 7

Every thread writes in its own lane

Every thread writes in its own lane

The event gate produced compact records, and now each visible row belongs to one Java thread with its own empty memory strip and cursor.

One thread appends a record by advancing only its own cursor, so no unrelated thread needs to acquire that cursor first.

Several threads can append during the same beat because their cells are separate. Their cursors advance in parallel instead of taking turns.

One private strip is now full, but the application thread still has more events to record. What should happen to that completed strip?

Pause and predict
What follows T0's full buffer?

The full strip detaches into global history while a fresh empty strip appears in its lane, so recording can continue after a brief handoff.

Switch the Write path control between Private lanes and Shared cursor. Compare independent appends with one queued cursor.

Private ownership keeps the common append path off busy application threads. Next, periodic stack samples will join the ordinary event stream.

Stage 4 of 7

Snapshots reveal the hot method

★ If you remember one thing · A few periodic stack snapshots make the repeatedly running method stand out without tracing every call.
Snapshots reveal the hot method

Private buffers can accept ordinary events, and profiling adds periodic snapshots that ask where a running thread is executing at selected moments.

The worked timeline contains a short parser, a long checkout loop, and a short response writer, with width representing time spent in each method.

Sample needles land at a fixed period. Each needle adds one stack reference instead of tracing every method entry and exit.

These snapshots capture only a few moments from the execution window. Which method should still lead after the sample hits are counted?

Pause and predict
Which method should lead the sampled profile?

Most needles land inside the long checkout span, so its computed profile bar grows longest even though JFR never traced every call.

Switch the Sample period control. Compare Checkout.run as a clear leader with the sparse three-way tie across methods.

Sampling trades complete tracing for bounded recurring work and a useful statistical signal for later diagnosis. Next, repeated stack details must become compact references.

Stage 5 of 7

Repeated stacks become small references

Repeated stacks become small references

The sampler produced stack-bearing events, but many snapshots point to the same methods, so repeating every frame would waste recording space.

In repeated form, each event carries another visible tower of stack frames even when that tower matches one already recorded.

Several events carry the same stack shape, so storing every tower repeats identical structure. How should matching samples share that information?

Pause and predict
How should matching stack samples reuse stored data?

The pool keeps each unique stack once and assigns it an ID, while sample events shrink into tokens that carry the matching reference.

The repeated towers collapse into one shared pool and a row of small IDs, so the saved structural units are visible beside the records.

Switch the Encoding control. Compare repeated frame units with the compact pool and its event references.

Reference pooling preserves stack identity while removing repeated structure from individual events throughout the recording. Next, those compact records need a self-contained file container.

Stage 6 of 7

Chunks preserve a rolling history

Chunks preserve a rolling history

The compact records now need a durable container, so JFR writes a chunk with a header and an event stream that carries parsing information.

Metadata records describe event types and fields, while checkpoint records carry shared constants such as classes, methods, threads, and stack traces.

Ordinary events and execution samples share that stream. Their small references resolve through checkpoint data stored inside the same chunk.

A continuous recording keeps producing chunks after its history limit is full. Which files should remain when the newest chunk is sealed?

Pause and predict
Which chunks remain after C5 fills a three-chunk window?

The newest sealed chunk joins the right edge while the oldest falls away, leaving a chronological window whose remaining chunks can still be parsed.

Adjust the Chunks kept control across its range. Compare whether trigger and pre-trigger context survive rotation for later diagnosis.

Chunk rotation bounds storage without breaking the parseability of retained history. Now let us connect every low-overhead decision in one final map.

Stage 7 of 7

The complete low-overhead path

The complete low-overhead path

We started at the event gate, where enabled settings and thresholds prevent unwanted duration events from entering the recording path.

We then gave every application thread a private buffer lane, so concurrent producers do not fight over one shared append cursor.

Periodic stack snapshots turned a computed execution timeline into a profile. The hottest method emerged without tracing every call.

Shared reference pools stored repeated stacks and methods once, while compact IDs carried those relationships into each matching event.

Filtering, private writes, sampling, and deduplication all reduce foreground work. Complete recording chunks preserve those compact observations after the moment passes.

Self-contained chunks connect every earlier piece into a rolling recording, and the worked numbers came from one deterministic model backed by official JFR specifications.

JFR remains practical in production because it filters early, writes privately, samples sparsely, reuses metadata, and rotates complete chunks.

Cheat sheet · 5 essential ideas

The whole story in 5 lines

JFR stays light by filtering early, writing privately, sampling sparsely, reusing metadata, and rotating complete chunks.

  1. Settings reject unneeded events before their data enters the recording path.
  2. Private write lanes let application threads append without sharing one hot cursor.
  3. Periodic snapshots trade perfect detail for a useful profile with bounded work.
  4. Shared IDs keep repeated stacks and methods from bloating every event record.
  5. Self-contained chunks turn compact records into a recoverable rolling history.
How does JFR avoid recording every duration event?
Enabled settings and thresholds reject unneeded duration events before their details reach the recording path.
Why do application threads not share one hot JFR append cursor?
Each application thread appends into a private buffer and hands off the full buffer to shared memory.
How can periodic samples reveal hot code?
Repeated snapshots land most often in methods that occupy more execution time, so their profile counts grow larger.
Why do sample events carry stack IDs?
JFR stores repeated stack and method structures once, then lets many events refer to them with compact IDs.
How does a continuous recording keep recent history parseable?
Each chunk carries the metadata and checkpoints needed for parsing, while retention removes the oldest complete chunks.