Understanding Memory Leaks in Android Apps

Understanding Memory Leaks in Android Apps

Imagine living in an apartment with your little waste bin outside, a bit close to the sitting room window. But every time the garbage truck/collectors come around, they skip emptying your waste bin. With each passing day your waste bin gets fuller and more smelly, the pungent smell may discourage you from laying on the sitting room couch. Then one day you decide to do something about your waste, you move your waste bin further to where it could be seen and picked up easily. Finally, your waste gets disposed and you can once again breathe a breath of fresh air.

This is exactly how a memory leak on an android app works. A memory leak occurs due to flimsy mistakes made while coding. And if an app has a memory leakage, the garbage collector can’t clear the heaps. Thereby causing the app to consume more memory which often leads to you receiving an error message stating; “ OutOfMemoryError”.

What is a Memory leak?

Memory leak is a programming error which causes an application to keep a reference to an object that is no longer needed. As a result, the memory allocated for that object cannot be reclaimed, eventually leading to an OutOfMemoryError crash.

One of the core benefits of Java is the automated memory management with the help of the built-in Garbage Collector (or GC for short). Now you might want to ask what is a Garbage Collector and its function.

What Is A Garbage Collector?



The garbage collector is a program which runs on the Java Virtual Machinewhich gets rid of objects which are not being used by a Java application anymore. It is a form of automatic memory management.

When a typical Java application is running, it is creating new objects, such as Strings and Files, but after a certain time, those objects are not used anymore. For example, take a look at the following code:

for (File f : files) {

 String s = f.getName();

 }

In the above code, the String s is being created on each iteration of the for loop. This means that in every iteration, a little bit of memory is being allocated to make a String object.

Going back to the code, we can see that once a single iteration is executed, in the next iteration, the String object that was created in the previous iteration is not being used anymore — that object is now considered “garbage”.

Eventually, we’ll start getting a lot of garbage, and memory will be used for objects which aren’t being used anymore. If this keeps going on, eventually the Java Virtual Machine will run out of space to make new objects.

That’s where the garbage collector steps in.

The garbage collector will look for objects which aren’t being used anymore and gets rid of them, freeing up the memory so other new objects can use that piece of memory.

In Java, memory management is taken care of by the garbage collector, but in other languages such as C, one needs to perform memory management on their own using functions such as malloc and freeMemory management is one of those things which are easy to make mistakes, which can lead to what is called memory leaks — places where memory is not reclaimed when they are not in use anymore.

Automatic memory management schemes like garbage collection make it so the programmer does not have to worry so much about memory management issues, so he or she can focus more on developing the applications they need to develop.

So what are some of the common mistakes that lead to memory leaks?

1. Broadcast Receivers:

Consider this scenario — you need to register a local broadcast receiver in your activity. If you don’t unregister the broadcast receiver, then it still holds a reference to the activity, even if you close the activity.

How to solve this? Always remember to call unregister receiver in onStop() of the activity.

Note: As Artem Demyanov pointed out if the broadcast Receiver is registered in onCreate()then when the app goes into the background and resumed again, the receiver will not be registered again. So it is always good to register the broadcastReceiver in onStart() or onResume() of the activity and unregister in onStop().

2. Static Activity or View Reference:

You are declaring a TextView as static (for whatever reason). If you reference activity or view directly or indirectly from a static reference, the activity would not be garbage collected after it is destroyed.

How to solve this? Always remember to NEVER use static variables for views or activities or contexts.

3. Singleton Class Reference:

you have defined a Singleton class as displayed below and you need to pass the context in order to fetch some files from the local storage.

The SingletonSampleClass. java

How to solve this? 

 Option 1: Instead of passing activity context i.e. this to the singleton class, you can pass applicationContext().

 Option 2: If you really have to use activity context, then when the activity is destroyed, ensure that the context you passed to the singleton class is set to null.

4. Inner Class Reference:

you have defined an inner class called LeakyClass.java as displayed below and you need to pass the activity in order to redirect to a new activity.

How to solve this? 

 Option 1: As mentioned before never create a static variable of an inner class.

 Option 2: The class should be set to static. Instances of anonymous classes do not hold an implicit reference to their outer class when they are “static”.

 Option 3: Use a weakReference of any view/activity. The garbage collector can collect an object if only weak references are pointing towards it.

5. AsyncTask Reference:

You are using an asyncTask to get a string value which is used to update the textView in OnPostExecute().

How to solve this?

 Option 1: We should always cancel the asyncTask when the activity is destroyed. This is because the asyncTask will still be executing even if the activity is destroyed.

 Option 2: NEVER reference a class inside the activity. If we definitely need to, we should set the class as static as static inner classes don’t hold any implicit reference to its parent activity class.

 Option 3: Use a weakReference of the textview.

6. Handler Reference:

Consider the following example — You are using a Handler to redirect to a new screen after 5 seconds.

How to solve this?

 Option 1: NEVER reference a class inside the activity. If we definitely need to, we should set the class as static. This is because when a 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.

 Option 2: Use a weakReference of the Activity.

7. Threads Reference:

We can repeat this same mistake again with both the Thread and TimerTask classes.

How to solve this?

 Option 1: Non-static anonymous classes hold an implicit reference to their enclosing class.

 Option 2: Close thread in activity onDestroy() to avoid thread leak.

8. TimerTask Reference:

The same principle is as Threads can be followed for TimerTask as well. A sample implementation for fixing memory leak is given below:

How to solve this?

 Option 1: Cancel timer in activity onDestroy() to avoid a memory leak.

So how do I check if my app is leaking?


I am sure everyone on the planet is aware of it but just in case, there is an awesome library called LeakyCanary that is great for finding out the leaks in our app along with the stack trace.

So basically to summarise:

 1. Use applicationContext() instead of activity context when possible. If you really have to use activity context, then when the activity is destroyed, ensure that the context you passed to the class is set to null.

 2. Never use static variables to declare views or activity context.

 3. Never reference a class inside the activity. If we need to, we should declare it as static, whether it is a thread or a handler or a timer or an asyncTask.

 4. Always make sure to unregister broadcastReceivers or timers inside the activity. Cancel any asyncTasks or Threads inside onDestroy().

 5. Always use a weakReference of the activity or view when needed.

Thanks for reading! I hope you enjoyed this article and found it useful, if so please hit the Clap button. Let me know your thoughts in the comments section and if in any way you find an error in my article please state it out in the comment sections.

Happy coding Fams!

To view or add a comment, sign in

More articles by Wisdom Nwokocha

Others also viewed

Explore content categories