Activity Context in static classes
Often you will want to wrap some of Android's classes in easier to use utility classes. Those utility classes often require a context to access the android OS or your apps' resources. A common example of this is a wrapper for the SharedPreferences class. In order to access Androids shared preferences one must write:
And so one may be tempted to create the following class:
now, if you call
init() with your activity context, the LeakySharedPrefsWrapper will retain a reference to your activity, preventing it from being garbage collected.
How to avoid:
When calling static helper functions, you can send in the application context using
When creating static helper functions, you can extract the application context from the context you are given (Calling getApplicationContext() on the application context returns the application context). So the fix to our wrapper is simple:
If the application context is not appropriate for your use case, you can include a Context parameter in each utility function, you should avoid keeping references to these context parameters. In this case the solution would look like so:
Anonymous callback in activities
Every Time you create an anonymous class, it retains an implicit reference to its parent class. So when you write:
You are in fact sending a reference to your LeakyActivity instance to foo. When the user navigates away from your LeakyActivity, this reference can prevent the LeakyActivity instance from being garbage collected. This is a serious leak as activities hold a reference to their entire view hierarchy and are therefore rather large objects in memory.
How to avoid this leak:
You can of course avoid using anonymous callbacks in activities entirely. You can also unregister all of your callbacks with respect to the activity lifecycle. like so:
Avoid leaking Activities with AsyncTask
A word of caution: AsyncTask has many gotcha's apart from the memory leak described here. So be careful with this API, or avoid it altogether if you don't fully understand the implications. There are many alternatives (Thread, EventBus, RxAndroid, etc).
One common mistake with
AsyncTask is to capture a strong reference to the host
This is a problem because
AsyncTask can easily outlive the parent
Activity, for example if a configuration change happens while the task is running.
The right way to do this is to make your task a
static class, which does not capture the parent, and holding a weak reference to the host
Avoid leaking Activities with Listeners
If you implement or create a listener in an Activity, always pay attention to the lifecycle of the object that has the listener registered.
Consider an application where we have several different activities/fragments interested in when a user is logged in or out. One way of doing this would be to have a singleton instance of a
UserController that can be subscribed to in order to get notified when the state of the user changes:
Then there are two activities,
What happens with this example is that every time the user logs in and then logs out again, a
MainActivity instance is leaked. The leak occurs because there is a reference to the activity in
Please note: Even if we use an anonymous inner class as a listener, the activity would still leak:
The activity would still leak, because the anonymous inner class has an implicit reference to the outer class (in this case the activity). This is why it is possible to call instance methods in the outer class from the inner class. In fact, the only type of inner classes that do not have a reference to the outer class are static inner classes.
In short, all instances of non-static inner classes hold an implicit reference to the instance of the outer class that created them.
There are two main approaches to solving this, either by adding a method to remove a listener from
UserController#listeners or using a
WeakReference to hold the reference of the listeners.
Alternative 1: Removing listeners
Let us start by creating a new method
Then let us call this method in the activity's
With this modification the instances of
MainActivity are no longer leaked when the user logs in and out. However, if the documentation isn't clear, chances are that the next developer that starts using
UserController might miss that it is required to unregister the listener when the activity is destroyed, which leads us to the second method of avoiding these types of leaks.
Alternative 2: Using weak references
First off, let us start by explaining what a weak reference is. A weak reference, as the name suggests, holds a weak reference to an object. Compared to a normal instance field, which is a strong reference, a weak references does not stop the garbage collector, GC, from removing the objects. In the example above this would allow
MainActivity to be garbage-collected after it has been destroyed if the
WeakReference to the reference the listeners.
In short, a weak reference is telling the GC that if no one else has a strong reference to this object, go ahead and remove it.
Let us modify the
UserController to use a list of
WeakReference to keep track of it's listeners:
With this modification it doesn't matter whether or not the listeners are removed, since
UserController holds no strong references to any of the listeners. However, writing this boilerplate code every time is cumbersome. Therefore, let us create a generic class called
Now let us re-write
UserController to use
As shown in the code example above, the
WeakCollection<T> removes all of the boilerplate code needed to use
WeakReference instead of a normal list. To top it all off: If a call to
UserController#removeUserStateChangeListener(StateListener) is missed, the listener, and all the objects it is referencing, will not leak.
Avoid memory leaks with Anonymous Class, Handler, Timer Task, Thread
In android, every developer uses
Anonymous Class (Runnable) at least once in a project. Any
Anonymous Class has a reference to its parent (activity). If we perform a long-running task, the parent activity will not be destroyed until the task is ended.
Example uses handler and Anonymous
Runnable class. The memory will be leak when we quit the activity before the
Runnable is finished.
How do we solve it?
- Dont do any long operating with
Anonymous Classor we need a
Static classfor it and pass
WeakReferenceinto it (such as activity, view...).
Threadis the same with
- Cancel the
Timerwhen activity is destroyed.
Common memory leaks and how to fix them
1. Fix your contexts:
Try using the appropriate context: For example since a Toast can be seen in many activities instead of in just one, use
getApplicationContext() for toasts, and since services can keep running even though an activity has ended start a service with:
Original article on context here.
2. Static reference to Context
A serious memory leak mistake is keeping a static reference to
View has an inner reference to the
Context. Which means an old Activity with its whole view hierarchy will not be garbage collected until the app is terminated. You will have your app twice in memory when rotating the screen.
Make sure there is absolutely no static reference to View, Context or any of their descendants.
3. Check that you're actually finishing your services.
For example, I have an intentService that uses the Google location service API. And I forgot to call
4. Check image and bitmaps usage:
If you are using Square's library Picasso I found I was leaking memory by not using the
.fit(), that drastically reduced my memory footprint from 50MB in average to less than 19MB:
5. If you are using broadcast receivers unregister them.
6. If you are using
java.util.Observer (Observer pattern):
Make sure to use
Detect memory leaks with the LeakCanary library
LeakCanary is an Open Source Java library to detect memory leaks in your debug builds.
Just add the dependencies in the
Then in your
Now LeakCanary will automatically show a notification when an activity memory leak is detected in your debug build.
NOTE: Release code will contain no reference to LeakCanary other than the two empty classes that exist in the