Garbage Collection (GC) is Android's automatic memory janitor.
Its job is simple: find objects in memory that your app no longer uses and free them up so the memory can be reused.
Think of it like:
You just moved into a house (heap). You keep buying stuff (objects).
After a while, your house gets cluttered. GC is the housekeeper who removes things you can't reach anymore — like that box you stuffed into the attic and forgot existed.
How GC Works in Android (Step-by-Step)
Android uses ART (Android Runtime), which has a generational, mostly concurrent GC.
Here's the typical lifecycle:
Root Set Scan
GC starts by checking GC Roots:
Thread stacks
Static variables
JNI global refs
These are like "entry points" into memory that are definitely still alive.
Reachability Analysis (Mark Phase)
ART uses a tricolor marking algorithm:
White: Objects not yet visited (possibly garbage)
Gray: Objects to be scanned
Black: Objects proven alive
It traverses references (like a graph search) and marks all reachable objects.
Sweep/Copy/Compact Phase
Unmarked (white) objects are freed.
Live objects may be compacted to avoid fragmentation.
Generational Optimization
Young Generation (Minor GC): Fast, collects short-lived objects (like temporary strings, small data objects).
Old Generation (Major GC): Collects objects that survived multiple GCs (activities, long-lived caches).
Concurrent Execution
Most of this happens while your app is running to reduce UI pauses.
Some steps are Stop-The-World (STW) but very short.
Visual Diagram
A[App Allocates Objects] --> B[Heap Fills]
B --> C[GC Triggered]
C --> D[Root Scan]
D --> E[Mark Reachable Objects (Tricolor Marking)]
E --> F[Collect Unreachable Objects]
F --> G[Compact / Reuse Memory]
G --> H[App Continues Smoothly]
When GC Happens
When heap usage crosses a certain threshold
When memory pressure is high (e.g., before OutOfMemoryError)
Explicit hint: System.gc() (just a request, not a guarantee!)
Code Example: Memory Leak & Fix
// Memory leak: Activity reference is never clearedobject SessionManager {var currentActivity: Activity?=null}
When Activity is rotated, the old instance stays in memory → GC sees it as still "reachable" → memory leak.