It’s Kind of Spontaneous.
First, we cannot force garbage collection to run (System.gc()). Sometimes it will but it’s unpredictable. In Java, garbage collection runs automatically in the background, managed by the Java Virtual Machine (JVM). The exact timing of its execution isn’t deterministic and depends on various factors, including:
- Heap Memory Usage: Garbage collection typically occurs when the JVM detects that the heap memory is running low and needs to free up space.
- JVM Implementation: Different JVM implementations (like HotSpot, OpenJ9, etc.) have their own algorithms and heuristics for deciding when to run the garbage collector.
- Garbage Collection Algorithm: The specific algorithm used (e.g., Serial, Parallel, CMS, G1) influences the collection strategy and timing.
- Manual Invocation: Although not recommended as a regular practice, developers can suggest the JVM to perform garbage collection by calling System.gc(). However, this call is only a suggestion, and the JVM may choose to ignore it.
Resource Constraints: If the system is running low on resources, the JVM may trigger garbage collection more frequently.
What are the steps to Garbage Collection in Java?
- Mark: GC walks through the object graph and marks the objects that are reachable as live
- Sweep: deletes unreachable objects
- Compact: compacts the memory by moving around the objects
GC collectors are called generational collectors since the heap is divided into 2 spaces: Young and old generation spaces. Young generation is for new objects and is divided into Eden, “Survivor 0” and “Survivor 1” spaces.
Old generation holds objects that survive for a long time.
Minor garbage collection runs in the Young Generation space. Major garbage collection runs across the entire heap.
Steps to GC:
- As your application runs, new objects get allocated to the Eden space.
- Some objects become unreachable.
- When the Eden space becomes full, and your application tries to create another object, and the JVM tries to allocate space on the Eden, the allocation fails and that causes Minor GC to run.
- All live objects are marked as reachable and those are Moved into Survivor space 0.
- The unreachable objects are swept and cleaned up.
- Each survived object is labeled with a counter to indicate how many times it’s survived the Garbage Collector.
- Application allocates new objects into Eden and some objects in the Survivor 0 space become unreachable. After Eden is full again, JVM tries to allocate space to Eden. It fails and triggers the Minor GC to run again.
- The new reachable objects are moved from Eden to Survivor 1.
- Survivor 0 reachable objects are moved from Survivor 0 to Survivor 1. Why? To avoid the compacting step.
- Unreachable objects from Eden and Survivor 0 are removed.
- Survivor 1 now holds objects that survived 1 cycle of garbage collection and 2 cycles of garbage collection (the ones moved from Survivor 0).
- And again, new objects are allocated to Eden. As Eden becomes full, Minor GC runs and moves the reachable objects from Eden and the reachable objects from Survivor 1 to Survivor 0. Unreachable objects from Eden and Survivor 1 are swept and cleaned up.
- This continues until a threshold number (i.e. 16) is reached. Whatever object has survived 16 Minor GC sweeps will be moved from Young Generation to Old Generation.
- A garbage collection thread keeps watching the Old Generation area and monitors when it becomes nearly full. When Old Generation is nearly full, the Major GC goes over both the Young and Old Generation (the entire heap) and does Mark, Sweep and Compacting which can be a performance hit.