Garbage Collection explained for Android Developers (and other JVM Platforms)
Note: Android runs on ART (Android Runtime) which is another runtime environment however GC works the same as on JVM.
You probably have learned that in java objects live inside the heap while references and variables live in the stack. In this post we will focus mainly on the heap. Objects inside a heap have different life spans due to garbage collection, which is very good, because fragments get created, destroyed and created over and over again (at least they should) and require the space to do so while other objects are wanted to live a little bit longer (a bitmap cache, a global state holder, a repository, etc.).
Many android developers I’ve met have heard of memory leaks but are not really aware of what they really are and how they are caused. Most of them know that a progress dialog could cause memory leaks if not handled and cleared properly. Despite knowing that, some don’t understand why it actually causes a leak. I have seen Developers setting a reference to a view / context in a static field, just to reuse it later for dependency injection, a sensor API, etc. This will always cause a memory leak if the view / context is not unreferenced after it is unusable (e.g. when the fragment is supposed to be destroyed).
If you don’t want your view (or any other object) leak memory, then avoid coupling it to an object which will live longer than your view. If you do it anyway, make sure you free your view from that reference once your view should die.
A memory leak is basically an object you are not using anymore but is still referenced. That object will live inside the heap blocking space for further allocations.
Structure of the Heap
The GC basically scans the heap and analyzes the objects. Unreferenced objects are marked for garbage collection (removal of the heap). However, the heap can grow very big and complex so it could be very inefficient to constantly scan all the objects inside the heap. How does this happen then?
Oracle has done some research and found out that most allocation of bytes happens in the early stage of an application and it decreases during during the life time.
For this reason the heap has been broken down into three categories. The Young Generation, the Old Generation and the Permanent Generation. Additionally, the Young Generation has 3 containers: eden, S0 and S1 (we’ll talk about them in a second). The objects inside the heap contain an age, which you can think of as an integer that is being incremented after certain operations. The Young Generation contains the freshly allocated objects, allowing short living objects to be removed quickly. A garbage collection that happens here is called minor garbage collection. The Old Generation contains older objects, the ones that are already alive for a longer time (Repositories, Application Class, etc.). Your view should actually have no business here. A garbage collection that happens here is called major garbage collection. The Permanent Generation consists of meta data required for the runtime environment (JVM, ART, etc.) which is used to describe classes and methods.
The rhythm of the Garbage Collection
As stated above, all new allocations happen first within the Young Generation part of the heap, inside eden to be specific.Means all new objects land here first. While the first objects land in eden, the subparts S0 (Survivor 0) and S1 (Survivor 1) stay empty. Once Eden is filled with objects completely a minor garbage collection happens which causes all unreferenced objects at that time to be kicked out of the heap. The objects that survived the garbage collection are the ones that are being referenced (and hopefully used by the application). The survived objects are being moved now into S0 (note that we are still inside the Young Generation part of the heap). Moving alive objects into S0 made eden empty again.
Once eden is full the GC gets triggered again, removing all unreferenced objects. This time, all referenced objects get moved to S1 unlike previously to S0. The objects inside S0 get their age incremented (remember, the integer?) and are then moved into S1. This is how the GC knows how old the objects inside the heap are. Eden and S0 are empty now, while S1 is filled with the objects that survived until now.
After some time passed eden is full again and now another garbage collection happens, what now? All unreferenced objects are removed again. This time all referenced objects are being pushed into S0. All currently living objects inside S1 get their age incremented and are then moved over to S0, too. Now we have 3 different generations of object inside S0.
Once objects reach a certain age, they get promoted and moved into the Old Generation part of the heap.
In the beginning eden S0 and S1 are empty.
- All objects are being put into eden
- eden is full and triggers a reference analysis on all objects inside the Young Generation Heap
- All unreferenced objects are removed (the actual garbage collection) and referenced ones are put into S0
- eden and S1 are empty, S0 has objects
- After a while eden is full with objects again and step 2 repeats
- Step 3 occurs now again, but this time all items are moved into S1
- All previously stored objects inside S0 get their age incremented and are then also moved into S1
- eden and S0 are empty, S1 has objects
- Time passes and eden is full -> Garbage Collection is triggered again
- All items get stored inside S0 and step 7 happens again, only with Objects inside S1 being incremented and moved into S0.
- Once an object has a certain Age it will get moved into the Old Generation store. All the 10 steps are repeated over and over again
This flow of garbage collection is also called Generational Garbage Collection. The older an object gets, the further it gets promoted (Young Generation -> Older Generation). The older your object gets the more seldom it will be touched by garbage collection.
I hope I could have helped you with understanding what memory leaks are, how they happen and why you should avoid having your views be referenced by objects that outlive it (e.g. static classes).
If you have any questions or something is unclear you can let me know in the comments. Feedback is always appreciated
Follow me on twitter if you’d like to be updated about further articles or just have a chat with me :-)