Why Full GC Happens Frequently and How to Prevent It in Java Applications
The article explains common scenarios that trigger frequent Full GC in Java, such as large object allocation, service timeouts, memory leaks, and old‑generation fragmentation, and offers insights on diagnosing and mitigating these issues to maintain application performance.
1. Real‑world Full GC Scenario Analysis
When a server receives a request, it creates various business objects; some of these may be large objects that are allocated directly in the old generation.
If after creating the business object the service calls another service that times out (e.g., Service C), the created object remains in JVM memory for the timeout duration (e.g., 15 seconds). Under high concurrency, many such objects stay resident, quickly filling the old generation.
Consequently, young‑generation objects are continuously promoted to the old generation.
As the old generation keeps receiving objects, it eventually runs out of space, triggering a Full GC.
2. Common Causes of Full GC
Full GC reclaims both the young and old generations (and often the metaspace), causing a stop‑the‑world pause that affects online services.
(1) Old‑generation space shortage – When an object needs to be promoted to the old generation but there is insufficient space, a Full GC is triggered. Objects survive multiple Young GCs, increase their age counter, and are promoted; if the old generation cannot accommodate them, Full GC occurs.
(2) Space allocation guarantee failure – Before a Young GC, the JVM checks whether the old generation has a contiguous block large enough for all surviving young‑generation objects. If not, and the flag HandlePromotionFailure is false (or true with additional conditions), a Full GC is performed.
(3) Explicit System.gc() call – Invoking System.gc() or Runtime.getRuntime().gc() suggests a Full GC. Although it is only a suggestion, most JVMs execute it unless disabled with -XX:+DisableExplicitGC.
(4) Memory leaks – Objects unintentionally retained (e.g., misuse of ThreadLocal or static collections) cannot be reclaimed, continuously filling the old generation and eventually causing Full GC.
(5) Severe old‑generation fragmentation – Even with enough total free space, fragmentation can prevent allocation of large objects, prompting a Full GC to compact the heap.
Occasional Full GC is normal, but frequent or long‑lasting Full GCs must be addressed.
3. Typical Business Scenarios That Easily Lead to Full GC
(1) Avalanche effect – When a dependent service times out, the current service may accumulate large amounts of data in memory, triggering Full GC.
(2) Large object allocation – Processing large files (e.g., hundreds of megabytes) by reading them entirely into a byte array creates a large object that is allocated directly in the old generation. Concurrent uploads can quickly exhaust old‑generation space.
(3) Memory leaks in background tasks – Caching task execution contexts in a static HashMap or ThreadLocal causes those objects to live for the entire application lifetime, growing the map until the old generation runs out of space.
(4) Unclosed resources – Database connections, file streams, and other resources not properly closed keep their associated Java objects and native memory alive, increasing memory pressure and causing frequent Full GCs.
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.
Lobster Programming
Sharing insights on technical analysis and exchange, making life better through technology.
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.
