When your code allocates memory to an object, but never de-allocates it.
What is memory Leak in Android ?
Whenever an object(A) which is not required anymore is being referenced by some other object(B) which is currently in use, would make garbage collector to consider the object(A) as an useful object .
Hence GC will not be able to remove the object(A) thinking somebody is still dependent on this. This eventually leads to Memory leaks.
How Garbage collector works?
Before we proceed further, let us understand briefly how Garbage collector works in Android.
“Garbage collection is the process by which Android programs perform automatic memory management using several GC algorithm e.g Mark and Sweep.
Whenever an android application starts, it creates one memory tree considering starting object as root of the tree. Root creates some other objects which can have its reference directly or indirectly and some other object being instantiated from these objects resulting in a chain of references and thus forms a memory tree.
Garbage collector starts from GC root and traverse to each and every objects reference linked directly or indirectly to the root and mark it as currently in use.All the unmarked object references are considered as unused and are eligible for garbage collection.
Now, just think of the scenario where some unused object which needs to removed from memory is being marked as active by GC only because someone has reference of it. Thus, it will not eligible for garbage collection resulting in memory leaks”.
How Memory leak can ruin your party ?
Whenever memory leaks happens, objects memory is not getting de-allocated even if they are unused, heaps memory keeps on increasing as the app is being used. This leads to the following problems:
1. As memory is required to create new objects to perform some tasks, app will have shortage of available memory .As a result Android system will trigger more frequent GC event than usual to claim the necessary memory.
More the GC has to run, more the application performance deteriorates.
GC events are stop-the-world events which means when GC happens, the rendering of UI and processing of events will stop.
“This impacts depend upon the types of GC events . When minor GCs will not be able to reclaim the memory, and the heap will keep on increasing, system will force a larger GC to kick off, which pauses the entire application main thread for around 50ms to 100ms. Since, Android has a 16ms drawing window and GC takes long than that, Android will start losing frames and lagging seriously .Generally, 100 to 200ms is the threshold beyond which users will perceive slowness in an application.”
2. If previous steps problem does not get solved, heap memory of the app will gradually increase. As a result, app will ask for more memory , however at one point of time system will refuse to allocate further memory which eventually leads to “OutOfMemoryError” and App crashes.
How to identify a memory leak?
1. Using Android Profiler :
The Memory Profiler is a component in the Android Profiler that helps you identify memory leaks and memory churn that can lead to stutter, freezes, and even app crashes. It shows a realtime graph of your app’s memory use and lets you capture a heap dump, force garbage collections, and track memory allocations.
To open the Memory Profiler, follow these steps:
1. Click View > Tool Windows > Profiler (you can also click Profile in the toolbar).
2. Select the device and app process you want to profile from the Android Profiler toolbar.
3. Click anywhere in the MEMORY timeline to open the Memory Profiler.
Alternatively, you can inspect your app memory from the command line with dumpsys, and also see GC events in logcat.
When you first open the Memory Profiler, you’ll see a detailed timeline of your app’s memory use and access tools to force garbage collection, capture a heap dump, and record memory allocations.
To help prevent these problems, you should use the Memory Profiler to do the following:
- Look for undesirable memory allocation patterns in the timeline that might be causing performance problems.
- Dump the Java heap to see which objects are using up memory at any given time. Several heap dumps over an extended period of time can help identify memory leaks.
- Record memory allocations during normal and extreme user interaction to identify exactly where your code is either allocating too many objects in a short time or allocating objects that become leaked.
Find complete Android Performance Patterns on YouTube.
2. Using LeakCanary :
LeakCanary is a open source library given by square for memory leak detection in Android.
It runs along with your application, dumps memory whenever required, identify potential memory leaks and gives a notification with a clean and complete stack trace to find the root cause of the leak.
Look at the article to know how LeakCanary works?
Common patterns that lead to memory leaks & how to fix them
1. Unregistered Listeners:
There are multiple scenarios when we register a listener to Activity or Fragment but forget to unregister it. These listeners hold strong reference to it and prevent it from being garbage collected even when it is unused.
2. Unregistered Local Broadcast receivers:
Sometimes we need to register a local broadcast receiver in an activity.
However, if we don’t unregister it, it holds the strong reference to the activity even if activity is no longer needed which prevent it to be garbage collected.
3. Inner Class Reference(AsyncTask in this case):
Inner class are very commonly used by many Android developers to perform various task .However, non-static Inner class unknowingly holds the implicit reference of the parent class which can lead to memory leaks.
1. Make the inner class as static.
2. Do not pass any Outer class(Activity/Fragment) reference to inner class. If at all, reference is required, pass it as Weak reference.
4. Anonymous Class Reference:
Similar to non static inner class, anonymous class also holds implicit reference to parent class. Therefore, it is recommended to use static inner class wherever anonymous class is intended to do long running process.
5. Handler Reference :
Handler is instantiated on the main thread, it is associated with the
Looper's message queue. Messages posted to the message queue will hold a reference to the
Handler so that the framework can call
Handler#handleMessage(Message) when the Looper eventually processes the message.It is very nicely explained here.
6. Thread & Timer Task :
We can come across the same pattern of memory leak while dealing with Thread and TimerTask as well.Solution is again similar as previously discussed.
Solution 1 : Create static inner class to avoid holding of an implicit reference to their enclosing class.
Solution 2: Close the thread in activity#onDestroy() to avoid thread leak. In case of TimerTask cancel it .
7. Other scenarios:
There are other obvious mistakes which can lead to memory leak and must be avoided by Android developers. These scenarios do not require detail discussion, so just pointing them out here:
- Assigning Activity instance to static reference.
- Passing Activity reference or context to a Singleton class.
- Passing Activity reference as listener to some other class and holding strong reference of it.
- Creating static view reference.
- Improper use of Context. Here is an excellent article to find out exactly which Context to use.
- Inefficient use of Bitmaps without recycling it. This may leads to OutOfMemoryError. Please find the proper way of handling it Here.
That is all about Memory leaks in Android. I hope this will help you to prevent, detect and fix the memory leak problems in your code.
Its time to build high performance and quality Android application .This will not only improve your app’s user experience, but will help to nurture you as a better developer as well.
Thanks for reading this article. You may also find the article on my Medium blog.