Why Mixed GC Doesn’t Empty the Old Generation in G1
Mixed GC in G1 only reclaims a portion of the Old generation that fits within the pause‑time budget, so seeing the Old region size stay high after a mixed pause does not mean G1 has failed, but rather reflects collection cost, survival rates, and budgeting constraints.
What Mixed GC Actually Collects
Mixed GC is not a full Old‑generation evacuation. During a pause it always collects all Young regions and only a subset of Old regions that are deemed worthwhile based on their garbage‑to‑live ratio and the pause‑time budget.
Mixed GC’s Collection Set (CSet)
The CSet for a Mixed pause consists of: All Young Regions + Some Old Regions Only Old regions with a high proportion of garbage (low survival rate) are selected, because each Old region incurs RSet scanning, live‑object copying, reference updating, and cleanup costs.
Pause‑Time Budget Constraints
After concurrent marking, G1 knows the live‑object statistics of each Old region, but it only includes a region in the CSet if the expected work fits within MaxGCPauseMillis. A tighter pause target makes G1 more conservative, excluding regions with many live objects or large RSets.
This explains why Mixed GC may appear frequently while Old usage does not drop significantly: the collector simply does not have enough budget to process many Old regions.
Survival‑Rate Threshold
The flag G1MixedGCLiveThresholdPercent (default 85) defines the maximum live‑object percentage an Old region may have to be eligible for Mixed collection. Raising the threshold allows more regions to be considered, increasing copy work and pause length; lowering it makes G1 pick only the dirtiest regions, shortening pauses but possibly leaving more Old space untouched.
Why Mixed GC Often Runs in Multiple Rounds
After a concurrent mark, G1 may split the candidate Old regions across several Mixed pauses, controlled by G1MixedGCCountTarget (default 8). This spreads the work to avoid long single pauses. The flag G1OldCSetRegionThresholdPercent caps the proportion of Old regions in any single CSet.
Heap‑Waste Percent
G1HeapWastePercent(default 5) tells G1 to stop the Mixed sequence when the reclaimable waste falls below the given percentage of the heap, preventing unnecessary work when the benefit is low.
Reading Mixed GC in Production
When analyzing logs, look at:
Frequency of Mixed pauses – high frequency indicates rapid Old growth.
Pause duration compared to Young GC – significantly longer Mixed pauses point to expensive Old work.
Before/After Old usage – >20% reduction means effective collection; <5% suggests poor candidate quality or high survival.
Number of Mixed rounds – 3‑8 rounds is normal; >10 may indicate overly conservative CSet selection.
Whether a Full GC follows – if Full GC still occurs, Mixed collection is not keeping up.
Case Study: E‑commerce Service
Metrics observed:
// Log snippet
[Concurrent Mark: 1.2s]
[GC pause (mixed), 0.1234 secs]
[Parallel Time: 115.3 ms]
[Object Copy (ms): Avg: 85.2]
[Scan RS (ms): Avg: 18.3]
[Update RS (ms): Avg: 8.5]
[Eden: 512.0M->0.0B Survivors: 64.0M->64.0M Heap: 2.8G->2.5G]Problems identified:
Mixed pause 120 ms (much higher than Young 35 ms).
Object copy dominates pause, indicating many live objects.
Large RSet scan time shows many cross‑region references.
Old usage fell only ~300 MB, a modest gain.
The service kept a large ConcurrentHashMap<Long, Product> in Old, updating lastAccessTime on every read, causing high survival and cross‑region references.
// Original cache code
ConcurrentHashMap<Long, Product> productCache = new ConcurrentHashMap<>();
public Product getProduct(Long id) {
Product product = productCache.get(id);
if (product != null) {
product.setLastAccessTime(System.currentTimeMillis()); // mutates Old object
}
return product;
}Optimizations applied:
Make Product immutable.
Store access timestamps in a separate map.
Limit cache size with LRU eviction.
Increase heap size.
// Optimized cache
class Product { private final Long id; private final String name; /* other immutable fields */ }
ConcurrentHashMap<Long, Product> productCache = new ConcurrentHashMap<>();
ConcurrentHashMap<Long, Long> accessTimeMap = new ConcurrentHashMap<>();
public Product getProduct(Long id) {
Product product = productCache.get(id);
if (product != null) {
accessTimeMap.put(id, System.currentTimeMillis()); // no mutation of Product
}
return product;
}After changes:
Mixed pause reduced from 120 ms to ~50 ms.
Old usage dropped from 70‑80% to 40‑50%.
Full GC frequency fell from hourly to daily.
Key Tuning Parameters
G1MixedGCCountTarget – desired number of Mixed pauses after a concurrent mark (default 8). Larger values spread work over more pauses; smaller values increase per‑pause work.
G1MixedGCLiveThresholdPercent – live‑object percentage threshold (default 85). Raising includes more regions; lowering makes G1 more selective.
G1OldCSetRegionThresholdPercent – max proportion of Old regions in a single CSet (default 10). Adjust to control pause length vs. amount reclaimed per pause.
G1HeapWastePercent – stop Mixed when reclaimable waste falls below this percent (default 5).
Evaluating Mixed GC Effectiveness
Check the following indicators:
Is the pause time within the MaxGCPauseMillis target?
Does Old usage drop noticeably (>20%) after a Mixed cycle?
Are the number of Mixed rounds reasonable (3‑8 typical)?
Is a Full GC still triggered shortly after Mixed?
If the answer to any of these is negative, investigate candidate region quality, survival rates, allocation pressure, and object lifetimes rather than merely tweaking the above flags.
Summary
Mixed GC in G1 reclaims all Young regions plus only those Old regions whose garbage proportion justifies the pause‑time cost. The collector’s behavior is driven by the pause‑time budget, live‑object thresholds, and waste‑percent settings. When Old usage does not decrease, examine candidate quality, survival rates, allocation speed, and object lifetimes; tuning the flags alone rarely solves the underlying problem.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
