Often early in our careers, We are so focused on developing new Apps with new features that we never actually care about the performance of our apps. This leads to technical debt and often degrades the quality. One of the contributing factor to poor performance is Memory leak. In the 8th episode of AndroIdiots Podcast we discuss Memory leaks in Android and how to avoid them with Jupneet .
Shouldn't Java solve this for us?
This is a very natural question that arises when we are coding in Java. Java has a Garbage Collector (GC) which uses mark and sweep algorithm to free up unused memory. In languages like C/C++, we have to manage allocation and deallocation of memory ourselves which can be error prone. Then why as a developer should we concern ourselves with memory leaks. Is GC at fault here?. NO. (A big and bold NO). Its us, the developers who make mistakes in our code which doesn't let Java's GC do what its best at.
Every object has got its own lifetime, after which its memory is deallocated. If some other object is holding onto this object, then GC will not be able to collect it and clear the memory. So when an Object's lifetime gets extended beyond its purpose, its then we get a memory leak.
What happens when memory leaks?
GC runs in short cycles (every few ms) and tries to clear all immediate dead objects. These short GC runs are concurrent and hence it doesn't slow down our app. But if there is excessive memory leak (meaning more memory usage), it forces the GC to run much more frequently. If the problem persists, a larger GC kicks in which completely halts the program execution to perform dead object collection. This makes the app unusable and Jank can be observed. Eventually this will lead to OutOfMemory exception and app will crash.
What causes Memory Leak?
Here are a few ways we leak memory in our apps:
- Static Context or Static Views:
Static members are referenced by their classes and are not cleared by GC. A static view (a view in turn holds on to an Activity/Fragment) or a static context, which are quite heavy objects, will remiain in memory until the User proactively kills the application hampering the App Experience.
Static objects are cleared off sometimes but its not certain. Read this for further explanation.
- Inner Classes or Anonymous Classes:
A very useful feature of Java when misused can cause potential memory leak. We have mentioned both in a single point because Anonymous classes are same as Inner Classes. They both implicitly hold on to the outer class reference. If an Inner/Anonymous class outlives the outer class, the latter will not be cleared.
- Unregistered Listeners:
A lot of times, we register for listeners but forget to unregister it. A very common example is registering for Location Updates. All we need to do is to get the LocationManager system service and register a listener for location updates. (say in an Activity). Now, LocationManager keeps a strong reference of the Activity. If we do not unregister, GC will not be able to remove Activity instance from memory because LocationManager is still holding on to it.
Bitmap is the in-memory representation of pixel data of an image. This can be huge at times. We have so many open source libraries like Glide, Fresco, Picasso that we usually don't have to worry about Bitmaps. But if we do, we need to be cautious because these are heavy objects. Check the following links for a better understanding of Bitmaps:
a) Managing Bitmap Memory
b) How Image Loading Libraries work
c) Reusing Bitmap
How to detect Memory Leaks?
- The easiest way to detect memory leak in an Android App is to use LeakCanary. Its this awesome Library by Square Engineering team which you can include in your app and it will spit out Memory leaks with proper trace in your debug builds.
- Android Studio Memory Profiler can help you identify usage peaks.
- Understanding how references work in Java, can help avoid Memory Leaks. For ex: When passing Context or View to an AsyncTask always use weak reference.
A bonus read: How Garbage Collection really works.
That's it folks. In this episode, we tried to understand Memory leaks and how to avoid them. Hope you enjoyed it.