Silly Leaks: Android

Guneet Singh
4 min readApr 23, 2020

Ugh, we all know about leaks due to inner classes, anonymous classes, static variables, etc. But what all these examples say is that they outlive the life to which they were associated. Hmm well said but what else could outlive and if they do how to find them?

I will point out some basic activities we do (or at least I did unknowingly) which left marks behind called the silly leaks but before that, I want to share some knowledge that I got in my experience:-

1: Library Leaks:

We must know that the library developers are also humans and they can also leave bugs that may cause leaks in your code. Library leaks are something we can't do much about but raise an issue on GitHub. Also, in every new android release bugs gets fixed and thereof it is very common to see a leak limited to a specific android version!

In this post, we will only be focusing on finding leaks though there are ways to fix library leaks as well!

2:Application Leaks:

Application leaks are the ones that are due to our silly mistakes which could be a result of not using APIs in the correct way. The only thing that one should remember is that every instance created in the system must be destroyed when its work is done and abiding it is up to the developer. Although most of the time GC itself collects all the garbage instances and frees up the memory wherever its algorithm can detect that an instance is no more useful!

3: LeakCanary:

LeakCanary is a simple library that makes finding memory leaks a breeze, at least for most of the cases. For others, you can use Android profiler, or LeakCanary also exposes API to track instances if you like to code instead! A caveat to LeakCanary is that it looks for both library and application leaks which sometimes feels more awful as it cannot identify whether a leak is a library or application until someone reports it here followed by adding the path to AndroidReferenceMatcher. After that leak will be shown with a description and where and how you can track it.

Enough of making sense, let’s end up with some examples of leaks that I found in my code followed by some useful resources that can help you digging further.

1: EditText

Using an EditText may lead to Activity context leaked in Android versions prior to Marshmallow, in my case I find it on Marshmallow which should not be the case according to google. I am not going to dig into why that happened but it happens! It is a library leak and also identified by LeakCanary so you can find a description for the same if you are curious about how does it look. I already have a sample on GitHub.

2: FragmentStack

Managing a fragment stack is always tedious and if not handled carefully often leads to fragment leaks.

Also, replacing a fragment doesn’t destroy the fragment but only its view if you put the fragment in the BackStack, so if you are storing any reference to the view and putting the containing fragment into the stack then this may lead to view not being Garbage Collected which we will talk about next.

3: View References

When you store view references to class fields, these references become bound to the instance of the class itself and it sometimes results in a memory leak when onDestroyView() is called but a reference to the view held by another instance is still in use. This can be fixed simply by setting the reference to null at onDestroyView() call:-

class AFragment extends Fragment{
private View aView;
...
@Override
public void onDestroyView (){
aView=null;
}
}

Another trick would be to use WeakReferences of views that can be garbage collected anytime when not needed.

4: ActionBar

This is a library leak that holds a reference to FragmentManagerImpl.mCreatedMenus and the issue is still not closed hence you won’t see a well-documented description in the logs.

5: Observers

You should know that the observers are bind to the controllers and only get destroyed with them so if you don’t need an observer anymore you should take care of it yourself. One major example of the Observer causing a leak is when you add an Observer which is holding a reference to the view. The view is destroyed irrespective of the fragment itself but as an Observer if holding a reference to it, the view won’t get GC.

A Simple way to do solve this leak is to store a reference to Observer in a variable and remove the observer calling LiveData.removeObserver(Observer:

private LiveData<Object> liveData;
private Observer<Object> observer;
...
liveData.observe(this,observer)
liveData.removeObserver(observer)

--

--