Why Java Objects Aren’t Collected Immediately – A Deep Dive into JVM Memory Allocation
This article explores how JVM memory is allocated, why objects created in methods are not reclaimed instantly, and demonstrates through experiments how Eden space, YGC, and GC behavior affect object lifetimes and overall heap utilization.
Preface
When I first received the request to artificially increase CPU and memory usage on low‑load servers, I was excited because it matched my specialty – writing bugs.
JVM Memory Allocation Review
I quickly wrote a small program to allocate memory and observed its behavior.
java -Djava.rmi.server.hostname=10.xx
-Djava.security.policy=jstatd.all.policy
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.port=8888
-Xms4g -Xmx4g -jar bug-0.0.1-SNAPSHOT.jarWith these startup parameters I could connect to the application via JMX to monitor memory and GC.
Initially I wondered whether the mem object would be reclaimed immediately after the method finished. Some people assumed it would, but my experiment proved otherwise.
After allocating 250 MB repeatedly, the memory usage curve rose sharply while GC did not trigger, and the object remained in memory.
Using jstat to inspect the heap confirmed that neither Young GC (YGC) nor Full GC (FGC) occurred; only the Eden region usage increased.
Only when the Eden space became almost full (≈98.83 %) did a YGC happen, which finally reclaimed the mem objects and caused the memory curve to drop.
The key takeaway is that an object is reclaimed only when the garbage collector runs, regardless of whether it is a local or global variable. The object must become unreachable, and a GC cycle must occur to collect it.
Objects are first allocated in the young generation’s Eden space, provided they are not too large. Large objects are allocated directly in the old generation.
Prioritize Allocation in Eden
Small objects are placed in Eden, but only if they fit; otherwise they go to the old generation.
Large Objects Directly Enter Old Generation
When I allocated 1000 MB, Eden could not accommodate it, so the allocation went straight to the old generation, increasing its usage by about 37 %.
Linux Memory View
Before starting the application the server used roughly 3 GB of memory. After launching the Java process, memory consumption rose to about 600 MB. To meet the requirement of higher load, I allocated small objects (≈800 MB) to keep the young generation at ~90 % and then allocated large objects to keep the old generation also around 90 %.
By carefully balancing allocations, I avoided triggering any GC cycles, resulting in a total memory consumption of about 3.5 GB without additional GC pauses.
Summary
Controlling JVM memory allocation precisely is not trivial; it requires a solid understanding of heap layout, GC triggers, and the distinction between reachable and unreachable objects.
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.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
