Java (JVM) GC glossary
Terms found in the GC logs of HotSpot and OpenJ9 JVMs (Serial, Parallel, CMS, G1, ZGC, Shenandoah). Each entry says what the term means, how it shows in a log and what it implies for the application.
Official documentation
- HotSpot Virtual Machine Garbage Collection Tuning Guide (Oracle)
- Available collectors (Oracle)
- JEP 271: Unified GC Logging
- The java command (Oracle)
- Troubleshoot Memory Leaks (Oracle)
Allocation Failure (GC cause)
The log cause of a collection started because a thread could not allocate in the space it asked for, usually because eden is full.
In Serial, Parallel and CMS logs, Pause Young (Allocation Failure) is the ordinary young collection triggered by a full eden: despite the name, nothing went wrong. Pause Full (Allocation Failure) means that a full collection was needed because even the old generation could not satisfy a request, a promotion or a direct allocation.
Repeated Pause Full (Allocation Failure) lines are a warning: the heap is too small or the application leaks memory. If an OutOfMemoryError: Java heap space follows, the last full collection could not free enough.
Official documentation: JEP 271: Unified GC Logging
Allocation rate
How many bytes per second the application allocates. It determines how often young collections occur.
Between two young collections, the amount allocated equals the free eden space. For a given eden size, doubling the allocation rate halves the interval between collections. A high rate is not a defect on its own, since short-lived objects are cheap, but it multiplies collections, leaves objects less time to die (so more are promoted) and, with concurrent collectors, can outrun the collector.
GC Doctor derives the rate from the heap before each collection and after the previous one. To reduce it, reuse objects, avoid boxing and temporary strings, presize collections, and profile allocations with Java Flight Recorder (jdk.ObjectAllocationSample).
Biased locking
An old optimization that assumed a lock is used by one thread only, making its acquisition nearly free. Disabled by default in JDK 15 and removed in JDK 18.
The first thread to take a lock marked the object as biased toward it. Another thread could take the lock only by revoking the bias, which required a safepoint. Revocations became costly and the benefit small as applications moved away from synchronized legacy collections (JEP 374).
In older JVM logs, safepoints named RevokeBias or BulkRevokeBias can explain pauses that no collection accounts for. On JDK 8 to 14, -XX:-UseBiasedLocking removes them.
Official documentation: JEP 374: Deprecate and Disable Biased Locking
Concurrent mode failure (CMS)
CMS only. The old generation filled up before the concurrent cycle finished, so the JVM stopped the application and ran a full compacting collection.
CMS had to start its concurrent cycle early enough to finish before promotion filled the old generation (it starts at the occupancy set by -XX:CMSInitiatingOccupancyFraction, adapted by default). If promotion was faster than the cycle, or if fragmentation left no free block big enough for a promoted object, the JVM logged concurrent mode failure and fell back to a serial full collection, with pauses of several seconds on large heaps.
CMS was deprecated in JDK 9 and removed in JDK 14, so this message only appears in older logs. Lowering the initiation threshold, enlarging the heap or switching to G1 are the usual remedies. Modern collectors have the same failure under other names: evacuation failure (G1), degenerated GC (Shenandoah), allocation stall (ZGC).
Concurrent phases
Collector work done while application threads keep running, such as marking live objects. It must finish before the heap fills up, otherwise the collector falls back to a stop-the-world collection.
Concurrent work trades CPU for shorter pauses: GC threads compete with the application for cores, and the barriers inserted in application code (write and load barriers) add a small constant overhead. G1 marks the old generation concurrently, ZGC and Shenandoah also relocate objects concurrently, CMS (removed in JDK 14) marked and swept concurrently.
In a log, concurrent phases appear with their own durations (Concurrent Mark Cycle, Concurrent Mark, Concurrent Rebuild Remembered Sets...). Their duration does not add to the pauses. They matter in two ways: a cycle that takes too long lets the heap fill up (see evacuation failure, concurrent mode failure and degenerated GC), and cycles that run back to back burn CPU. GC Doctor reports the share of time spent in concurrent work and its overlap with pauses.
Degenerated GC (Shenandoah)
When a concurrent cycle cannot keep up with allocation, Shenandoah stops the application and finishes the cycle in a pause.
Shenandoah normally works concurrently. If the application allocates faster than the collector frees memory, free memory runs out. Shenandoah first slows down the allocating threads (pacing), then, if that is not enough, switches to a degenerated cycle: the rest of the concurrent cycle runs in a stop-the-world pause. If even that does not free enough memory, it falls back to a full collection.
A log line such as Pause Degenerated GC (Mark) names the phase where the cycle degenerated. Frequent degenerated cycles mean that the heap is too small for the allocation rate or that the cycle starts too late: give the collector more headroom with a larger heap, or change the heuristics (-XX:ShenandoahGCHeuristics). ZGC faces the same situation as an allocation stall, where the allocating thread waits until memory is freed.
Official documentation: JEP 379: Shenandoah, a Low-Pause-Time Garbage Collector (Production)
Deoptimization
The JVM abandons compiled code and goes back to the interpreter because an assumption made by the JIT compiler is no longer valid.
The JIT compiler optimizes aggressively using runtime profiling, for example by assuming that only one class implements an interface or that a branch is never taken. When the assumption fails (a new class is loaded, an uncommon trap is hit), the compiled frames are converted to interpreter frames. Mass deoptimizations run at a safepoint and appear in -Xlog:safepoint as Deoptimize operations.
They are not garbage collection, but they stop the application and so show up in the same pause analysis. Frequent ones after the warm-up suggest classes loaded at runtime or code paths that keep changing.
Eden
The area of the young generation where new objects are first allocated. When it is full, a young collection starts.
Application threads allocate in eden by bumping a pointer inside their own thread-local allocation buffer (TLAB), which makes allocation very cheap. When a thread cannot get more eden space, the JVM stops the world and starts a young collection (cause Allocation Failure in Serial and Parallel, G1 Evacuation Pause in G1).
The time between two young collections is the eden size divided by the allocation rate. A 512 MiB eden and an application allocating 256 MiB per second collect every two seconds. A larger eden lowers the frequency of collections; it does not make each pause shorter.
Evacuation failure / to-space exhausted (G1)
G1 could not copy a live object because no free region was left to receive it. The log shows to-space exhausted.
During a young or mixed collection, G1 copies (evacuates) live objects into free regions. If it runs out of free regions, it cannot move everything: it leaves the objects it could not copy in place, finishes the pause by repairing references and keeps those regions. Such a pause is much longer than usual, and a full collection often follows, the slowest collection of all.
Causes: too little free heap when the collection starts (the concurrent cycle started too late, the allocation rate is high, many humongous objects), or a heap too small for the live data. Remedies: increase the heap, lower -XX:InitiatingHeapOccupancyPercent or leave adaptive IHOP on so that the concurrent cycle starts earlier, raise -XX:G1ReservePercent (10 by default) and reduce humongous allocations.
Official documentation: Garbage-First (G1) Garbage Collector (Oracle), Garbage-First Garbage Collector Tuning (Oracle)
Explicit GC (System.gc())
A collection requested by code or by a tool instead of by the collector itself, with the cause System.gc() or Diagnostic Command.
System.gc(), Runtime.gc() and some libraries (NIO direct buffer cleanup, RMI distributed GC, which runs every hour by default) trigger a full collection, shown as Pause Full (System.gc()). Heap inspection tools such as jmap -histo:live and jcmd GC.run also trigger one. Explicit collections are stop-the-world and can last seconds on a large heap.
They are rarely useful. -XX:+DisableExplicitGC ignores them; with G1 or CMS, -XX:+ExplicitGCInvokesConcurrent turns them into concurrent cycles. Pauses that recur at fixed intervals, one hour apart, usually come from RMI.
Official documentation: The java command (Oracle)
Forwarding pointer
A pointer or table that tells where a moved object now lives, so that threads find the new copy.
While a region is being evacuated, the old and the new copy of an object both exist. The forwarding information says which one is current: Shenandoah stores it in the object itself, ZGC keeps a forwarding table for each relocated page. Once all references to the moved objects have been updated, the old region is released and the forwarding information is discarded.
This information needs memory of its own, which is part of the collector overhead and one reason why ZGC and Shenandoah need some headroom beyond the live data set.
Full GC
A stop-the-world collection of the entire heap: mark, then compact. The slowest collection; in a healthy application it is rare or absent.
Typical triggers: no room to promote or allocate after a young collection (Allocation Failure), an explicit System.gc() call, the metaspace threshold, a heap inspection or heap dump request, a concurrent collector that fell behind. The cost grows with the live data, since all of it must be marked and moved: seconds on a multi-gigabyte heap.
Serial and Parallel collect their old generation with a full collection by design. G1 uses a parallel full collection since JDK 10, but it remains a last resort. The sign of a problem is frequent full collections that reclaim little: the live data set is close to the heap size, and the application either leaks memory or is under-provisioned. Read the cause in the log line, Pause Full (cause), then the heap after the collection. GC Doctor lists every full GC with its cause and its heap before and after.
GC overhead limit exceeded
An OutOfMemoryError raised when the JVM spends nearly all its time in GC and recovers almost nothing.
Parallel GC raises java.lang.OutOfMemoryError: GC overhead limit exceeded when more than 98 percent of the time is spent in GC and less than 2 percent of the heap is recovered, over several consecutive full collections (-XX:+UseGCOverheadLimit, on by default). It is a symptom, not a cause: the live data set is larger than the heap, or a leak keeps filling it.
Look in the log for back-to-back Pause Full lines that reclaim almost nothing, then analyze a heap dump (jcmd GC.heap_dump) to find who retains the memory. Raising -Xmx postpones the failure but does not fix a leak.
Official documentation: Troubleshoot Memory Leaks (Oracle)
Humongous object (G1)
In G1, an object whose size is at least half a region. It is allocated directly in contiguous old regions and bypasses the young generation.
G1 splits the heap into equal regions of 1 MiB to 32 MiB (a power of two chosen from the heap size; -XX:G1HeapRegionSize overrides it). Large arrays, buffers or strings can exceed half a region. They then occupy one or more contiguous regions entirely, and the unused end of the last region is wasted.
This causes three problems: fragmentation (contiguous free regions are needed), early concurrent cycles (a humongous allocation can start a Concurrent Start collection; the log cause is G1 Humongous Allocation) and, when the heap is nearly full of them, evacuation failures or full collections. Dead humongous objects can be reclaimed eagerly during young collections, but long-lived ones stay until a concurrent cycle or a mixed collection frees them.
Remedies: raise the region size, break up large buffers, or reuse them. The Humongous view of GC Doctor lists the collections concerned.
Official documentation: Garbage-First (G1) Garbage Collector (Oracle)
IHOP (G1)
Initiating Heap Occupancy Percent: the old generation occupancy at which G1 starts a concurrent marking cycle.
A concurrent cycle must finish before the old generation fills up. If it starts too late, G1 hits evacuation failures or a full collection; if it starts too early, the collector runs more often than needed and wastes CPU. By default G1 adapts the threshold automatically (adaptive IHOP) from the observed marking time and allocation rate, with -XX:InitiatingHeapOccupancyPercent (45) as the initial value. -XX:-G1UseAdaptiveIHOP gives a fixed threshold.
A Concurrent Start pause (cause G1 Evacuation Pause or G1 Humongous Allocation) marks the beginning of a cycle. If cycles start right after the previous one ends, the old generation is under pressure.
Official documentation: Garbage-First (G1) Garbage Collector (Oracle), Garbage-First Garbage Collector Tuning (Oracle)
Latency
What the GC costs a request: the pauses it adds to response time, notably in the tail.
Averages hide the problem. A collector with a 1 ms average pause can still produce a 500 ms pause once a minute, and that is what the 99th percentile of client latency shows. Look at the maximum pause and the 99th percentile pause, then at how often long pauses occur. Cumulative effects matter as well: several pauses in the same request add up.
The pause reported in the GC log is a lower bound of the stall seen by the application, because the time to reach a safepoint and the time to resume threads are outside it.
Live data set
The memory the application really needs: what stays reachable after a full collection. It sets the minimum useful heap size.
Measure it as the heap occupancy right after a full or old collection. After a young collection the old generation may still contain garbage, so it overestimates. As a rule of thumb, a heap of two to four times the live data set leaves enough room for allocation. The smaller the heap, the more often the collector runs and the more CPU it takes; the larger, the less often, but the pauses of some collectors grow.
A live data set that grows over hours without leveling off is the signature of a memory leak; one that stays stable but close to the heap size means the heap is too small. GC Doctor shows the heap after each collection and flags a steady increase.
Load barrier (ZGC, Shenandoah)
Code inserted when the application reads an object reference, so that the collector can find or fix a reference to an object that may have moved.
Concurrent compaction means that the collector moves objects while threads run, so a reference read from the heap may be stale. The barrier checks the reference (ZGC encodes state in bits of the pointer, Shenandoah checks whether the object is in the collection set) and, if needed, relocates the object or looks up its new address. It then repairs the reference in the heap (self-healing), so later reads are fast.
The cost is a small constant overhead on every reference load, in exchange for pauses that do not depend on the heap size. It is one reason why the throughput of ZGC and Shenandoah is a bit lower than that of Parallel or G1 on the same workload. Barriers do not appear in GC logs; their effect shows in CPU use.
Official documentation: The Z Garbage Collector (Oracle), JEP 379: Shenandoah, a Low-Pause-Time Garbage Collector (Production)
Mark and compact
The two steps of a full collection: find every live object (mark), then slide them together to create one contiguous free area (compact).
Marking walks the object graph from the roots. Compaction removes fragmentation: afterwards, allocation is a pointer bump and large objects find room. The price is that the references to every moved object must be updated, so all threads must be stopped.
Serial and Parallel use mark and compact for the old generation. G1 and the concurrent collectors avoid compacting the whole heap at once by evacuating selected regions only. Sweeping without compacting (CMS, Go) is cheaper but leaves free space fragmented.
Metaspace
Native memory, outside the Java heap, holding the metadata of loaded classes: structures, methods and constant pools. It replaced the permanent generation in JDK 8.
Metaspace grows when classes are loaded and shrinks when their class loader is garbage collected. By default it is limited only by the available native memory. -XX:MaxMetaspaceSize sets a cap, and reaching it throws OutOfMemoryError: Metaspace. -XX:MetaspaceSize sets the threshold at which the first collection is triggered (log cause Metadata GC Threshold).
Typical causes of growth: frameworks that generate classes at runtime (proxies, bytecode generation, scripting), redeployments that leak class loaders, or a limit set too low for the number of classes. A saw tooth with Metadata GC Threshold collections means that the threshold is too low and every increase triggers a full collection: set MetaspaceSize higher. Since JDK 16 (JEP 387) unused metaspace is returned to the operating system more promptly.
Official documentation: JEP 387: Elastic Metaspace, The java command (Oracle)
Mixed collection (G1)
A G1 pause that evacuates the young regions plus a selection of old regions containing the most garbage.
After a concurrent marking cycle, G1 knows how much live data each old region holds. During the space-reclamation phase that follows, each Pause Young (Mixed) adds some of the most garbage-rich old regions, the cheapest to evacuate, to the collection set. The phase ends when the reclaimable fraction falls below -XX:G1HeapWastePercent (5 percent by default) or when the planned number of mixed collections (-XX:G1MixedGCCountTarget, 8) is done. The pause time goal limits how many regions go in each pause.
Mixed collections are G1's way of reclaiming the old generation without a full collection. If the old generation grows faster than mixed collections free it, G1 eventually hits evacuation failures and full collections. Long mixed pauses often point to old regions with a lot of live data or with large remembered sets.
Official documentation: Garbage-First (G1) Garbage Collector (Oracle)
Old generation
Where objects that survived several young collections are tenured. It is collected rarely, and collecting it costs more because most of what it holds is alive.
The occupancy of the old generation right after each old collection is the best signal of a leak or of premature promotion. If it keeps climbing, the application retains more and more data (a leak, an unbounded cache). If it jumps in steps, short-lived data is promoted too early, often because the survivor space is too small or the allocation rate is high.
Collectors reclaim the old generation in different ways: Serial and Parallel compact it during a full stop-the-world collection; CMS (removed in JDK 14) swept it concurrently; G1 marks it concurrently and then reclaims it in small steps with mixed collections; ZGC and Shenandoah collect the whole heap concurrently.
Pause / Stop-the-world
A period during which every application thread is halted so that the collector can work on a heap that does not change under its feet.
Pauses are what users feel as latency: a request that arrives during a pause waits for the whole pause. A log line such as Pause Young (Normal) (G1 Evacuation Pause) 24M to 4M (256M) 3.2ms gives the cause, the heap before and after the collection, the committed heap size and the duration.
Not all collection work is a pause. Modern collectors (G1, ZGC, Shenandoah) do most of the marking concurrently and keep the stop-the-world phases short, but some work always needs one: starting and ending a marking cycle, evacuating live objects in G1, or a fallback full collection. The length of a pause grows with the amount of live data to copy or scan, not with the amount of garbage; ZGC and Shenandoah are the exception, their pauses are almost independent of the heap size.
GC Doctor charts every pause over time and reports the longest one, the 99th percentile and the share of time spent paused.
Official documentation: JEP 271: Unified GC Logging
Promotion / Tenuring
Moving an object from the young generation to the old one, because it survived enough young collections or because the survivor space was full.
Each survivor of a young collection gets one year older. The tenuring threshold (-XX:MaxTenuringThreshold, 15 by default) is the age at which objects are promoted. Parallel and G1 lower it dynamically so that survivors fit in the survivor space. When they do not fit, the excess is promoted whatever its age: this is premature promotion.
Promotion has two costs. The object is copied once more, and it will now die in the old generation, where it is reclaimed by a costlier collection. A promotion volume that is high compared with the allocation rate, or old collections that reclaim a lot, suggest that the young generation is too small or that survivors are too large. GC Doctor charts the bytes promoted by each collection.
Region
A fixed-size block of the heap. Region-based collectors (G1, ZGC, Shenandoah) reclaim memory region by region instead of as one contiguous generation.
G1 divides the heap into about 2048 regions of equal size (1 MiB to 32 MiB). Each region is given a role as needed: eden, survivor, old or humongous. This lets G1 choose which regions to collect to meet its pause goal. ZGC uses pages of 2 MiB (small objects), 32 MiB (medium) or larger sizes for large objects, and Shenandoah also divides the heap into regions.
A region layout avoids a fixed split between young and old and allows partial compaction. The downside is internal waste when objects do not fill regions, as with humongous objects in G1.
Official documentation: Garbage-First (G1) Garbage Collector (Oracle), The Z Garbage Collector (Oracle)
Remembered set
A structure recording which parts of the heap hold references into a given area, so that this area can be collected without scanning everything else.
A generational collector can collect the young generation alone only if it knows every old object that points into it. Instead of scanning the old generation, it consults the remembered set (a card table in Serial and Parallel, one set per region in G1) that the write barrier maintains.
In G1, remembered sets also allow collecting any subset of old regions, which is what makes mixed collections possible. They are the main memory overhead of G1 (a few percent of the heap, more with many cross-region references), and scanning them takes time in each pause (Scan Heap Roots). Rebuilding them is a concurrent phase after marking (Concurrent Rebuild Remembered Sets).
Root scanning
Finding the starting points of reachability: thread stacks, static fields, JNI handles, registers and other runtime structures.
Every collection begins with the roots, since an object is alive only if it can be reached from them. Time grows with the number of threads and the depth of their stacks, with the number of loaded classes (class loader roots) and with the number of JNI references. In G1 logs it appears as Ext Root Scanning, with one value per worker thread.
A long root scanning time with little live data points to many threads, huge stacks or many classes. ZGC and Shenandoah scan thread stacks concurrently, which keeps this work out of the pause.
Safepoint
A point in the execution of Java threads where their state is fully described, so that the JVM can safely inspect or change it.
A VM operation (a stop-the-world collection, a heap dump, deoptimization of many methods, a thread dump, biased lock revocation before JDK 18) requests a safepoint. Every Java thread runs until it reaches a poll and parks there, the operation executes, then the threads resume. The delay between the request and the moment the last thread reaches the safepoint is the time to safepoint, and a GC log that does not record it hides it from the reported pause.
A long time to safepoint is typically caused by a thread stuck in a long counted loop without a poll, or by a thread slow to be scheduled. Enable -Xlog:safepoint to record it. When the application stalls for longer than the collection pause in the GC log, look at the safepoint time. The Safepoints view shows each operation, its time to safepoint and its duration.
Official documentation: JEP 271: Unified GC Logging
Survivor space
A small area of the young generation, in two halves, that holds objects which survived at least one young collection but are not old enough to be promoted.
At each young collection, survivors are copied from eden and from the previous survivor space into the other one, and their age grows by one. Keeping them in the young generation gives short-lived objects extra chances to die before promotion. G1 manages survivor regions as a set instead of two fixed halves.
The size of the survivor space limits how many objects can stay young: if survivors overflow it, the excess is promoted immediately. With the gc+age=trace tag, the log shows how many bytes are at each age; a lot of bytes at the oldest ages means that the objects are on their way to the old generation. GC Doctor draws this distribution as a heatmap when the log contains it.
Tenuring threshold
The age, counted in young collections survived, at which an object is promoted to the old generation.
-XX:MaxTenuringThreshold sets the maximum (15 by default). At each young collection the collector computes a dynamic threshold: if the survivors of ages up to n fill more than the target survivor ratio (-XX:TargetSurvivorRatio, 50 percent) of the survivor space, the threshold becomes n.
A threshold that drops to 1 shows that survivors overflow: objects are promoted after a single survival, which is premature promotion. A threshold that stays at 15 with few survivors is the healthy case. GC Doctor charts the threshold and the age distribution when the log provides them.
Throughput
The share of time the application spends on useful work rather than in GC pauses.
A throughput of 99 percent means one second of pauses per 100 seconds. Throughput-oriented tuning (Parallel, large heaps) accepts longer and rarer pauses. Latency-oriented tuning (ZGC, Shenandoah, G1 with a low pause goal) accepts more frequent, shorter work and spends more CPU in the collector.
GC Doctor computes throughput from the pauses of the selected range. It ignores concurrent work, which consumes CPU without stopping the application, so read it together with the CPU view.
TLAB
Thread-local allocation buffer: a private slice of eden handed to each thread so that allocation needs no locking.
A thread allocates by bumping a pointer in its TLAB. Only when the buffer is exhausted does it ask for a new one from the shared eden, a slower path with synchronization. The JVM sizes TLABs adaptively from the allocation rate of each thread. An object larger than the remaining TLAB space is allocated outside it, directly in eden.
With -Xlog:gc+tlab=trace the log shows per-thread allocation and waste. The JFR events ObjectAllocationInNewTLAB and ObjectAllocationOutsideTLAB tell where allocations come from; allocations outside a TLAB are slower and typical of large arrays.
Write barrier
Code run by the application each time it stores an object reference in the heap. It records the change so that the collector does not have to rescan everything.
Generational collectors use a write barrier to maintain the remembered set: when an old object is made to point to a young one, the barrier marks a card (a small memory range) as dirty, so the next young collection scans only dirty cards instead of the whole old generation. G1 also uses a barrier for concurrent marking (SATB, snapshot at the beginning) that records references overwritten while marking runs, so that live objects are not lost.
The overhead is small per store but constant, and refining dirty cards in G1 consumes background threads. In GC logs it shows as update remembered set time during pauses and as concurrent refinement.
Young generation
The part of the heap where new objects are allocated: an eden space plus survivor spaces (in G1, a set of regions). It is collected often because most objects die young.
The weak generational hypothesis says that most objects become unreachable soon after they are allocated. A young collection exploits it: it only looks at the young generation, copies the few survivors to a survivor space or promotes them to the old generation, and reclaims everything else at once. Its cost is proportional to the survivors, not to the garbage.
Young collections are stop-the-world in Serial, Parallel and G1; generational ZGC runs them concurrently. A bigger young generation means fewer collections and more time for objects to die before they are promoted. G1 resizes it by itself to meet its pause goal (-XX:MaxGCPauseMillis, 200 ms by default).
Official documentation: Available collectors (Oracle)