This post discusses the issue of memory leaks and how to handle them efficiently and what are the tools available which help developers in managing the memory leaks. After working on PR #824 opened under PSLab – Android repository I have got a greater idea about how to manage the memory efficiently and what are the tools that should be used to ease the work.
What are memory leaks and how it affects the quality of app?
In simple words, memory leaks happen when you hold on to an item for long after its purpose have been served. It is as simple as that. But let us dive in further to understand more about this topic. Programming languages like C and C++ need memory management done by user whereas in higher level languages like Java, Python, etc. low-level memory management and garbage collection is done automatically by the system. But it is due to programming faults that memory leaks happen and so care needs to be taken with higher level languages too in handling memory efficiently.
In Android or say in any OS (operating system), every item has to be destroyed or say deleted or freed from the memory after its purpose is served. But if the reference of this object is passed on to any other object which has a greater time of importance than this, then it will try to hold this object for long and so the garbage collector won’t be able to collect it and so there will be memory leaks in the code. This is how memory leaks occurs inside an app.
Now, the issue of memory leaks is utmost important among developers as due to it, the app becomes slow, laggy, eats up a lot of memory and the app crashes after some time of use which creates a very bad user experience. As the user keeps on using the app, the heap memory also keeps on increasing and due to memory leaks, this heap can’t be freed by the garbage collector. Thus, all these issues contribute to making the threads or processes running inside the app slower and it can result in a lag of time from microseconds to milliseconds too!!
How can you detect these memory leaks?
This blog is mostly for Android developers and so I will use the environment of Android Studio for reference. For controlling memory leaks, Android Studio has a very powerful tool named Monitors. There are individual monitors not only for memory usage but for CPU, GPU, and network usage as well. An example of it is shown in figure 1 below.
Figure 1. Monitor in Android Studio
Now how to observe the graphs that are produced by Monitors to see if there are any memory leaks? The first alarming case is when the memory usage graph constantly increases and doesn’t come down as time passes and even not decreases when you put the app in the background. The tools which are used to undo memory leaks as soon as they are found are:
- Allocation Tracker: The allocation tracker comes with an indicator to show the percentage of memory allocated to different types of objects in your app. The developer can have a clear idea about which object is taking what amount of memory and which objects are exceeding the memory limit. But it is itself not enough as the developer needs other tools to dump the extra memory.
- Leak Canary Library: It is the most used library by developers to check for memory leaks in an app. This library runs along with app and dumps memory when needed, looks for potential memory leaks and gives a notification for a memory leak with a clean trace to find the root of the leak with sub-roots attached to it as shown in figure 2 :
Figure 2. Screenshot from Leaks application made by Leak Canary for PSLab app
It is clearly visible from the image that the applications show the root of the memory leak with an indication of how much memory is leaked in the toolbar.
Explanation of leak shown in figure 2 :
In the PSLab app, there is a navigation drawer consisting of all main functionalities in it. It is as shown in figure 3 :
Figure 3. Navigation drawer in PSLab
The memory leak as shown in figure 2 originated in the following steps :
- It started with ArrayList which is here the list of items as shown in figure 3.
- After it comes to the ScrollContainer which helps in scrolling this list on small screens.
- Then comes the Drawer Layout which is the actual layout seen in figure 3 that slides over the main layout which is here the Instruments layout.
- At last, comes the InputMethodManager which is introduced by Leak Canary library which watches the activity that is being opened.
- Here, InputMethodManager kept watching on Drawer Layout but after closing the layout too it referenced it which is due to the source code of LeakCanary Library and so memory Leak occurred.
How to stop this leak from occurring ?
A simple way is to add a transparent activity as soon as the layout is closed for a very small time i.e. 500 ms so that the reference watcher gets shifted from the actual layout. This solution is based on the article published on Medium [5].
How to implement Leak Canary in your app?
Below is the step-by-step guide on implementing Leak Canary library in your app to implement a watcher for memory leaks :
-
- Add dependencies (App Level) in your project to implement Leak Canary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
-
-
- debugImplementation – For debug flavor of app
- releaseImplementation – For release flavor of app
- testImplementation – For testing the current flavor of the app
-
Add dependencies according to the need for the application.
Add Realm dependencies (Project Level) in your app to create a database which can be used by Leak Canary to maintain and provide crash reports as shown in the figure above.
NOTE: Any database can be used here according to the need of the app
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:0.88.2"
}
}
apply plugin: 'realm-android'
App-level dependency :
compile 'io.realm:android-adapters:2.0.0'
- Add an activity class in your application to construct the Leak Canary for your entire application. In PSLab Android application, it was made as under :
package org.fossasia.pslab;
import android.app.Application;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
import io.realm.Realm;
public class PSLabApplication extends Application {
public RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
Realm.init(this);
initializeLeakCanary();
}
private void initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
return;
}
refWatcher = LeakCanary.install(this);
}
}
Explanation of the above-implemented code :
- First import all the necessary libraries
- Realm.init(this) is used to initiate the database as soon as the layout of the Leak Canary is ready to work so that before any crashes, the database is ready to accept the entry
- initializeLeakCanary() method first checks if the analyzer is in the process i.e. if the Leak Canary is already initiated so that there’s no need to again initiate it else a reference watcher is initiated with variable refWatcher which looks out for any potential memory leaks
After this, you can provide a watcher with an object to watch by writing :
refWatcher.watch(object);
Now your app is ready to handle any case of memory leaks and thus the developer can find the root of the issue if any and can solve it with ease. The app will now work 94% more efficiently than what it used to be with memory leaks. Thus, a greater user experience can be provided now but in the backend!!
Resources
- How to use Leak Canary – Article on Stack Overflow
- Everything you need to know about memory leaks – Article on medium.com
- Leak Canary: Detect all memory leaks -Another great article on medium.com
- https://github.com/square/leakcanary – Actual GitHub repo of Leak Canary library
- https://medium.com/@amitshekhar/android-memory-leaks-inputmethodmanager-solved-a6f2fe1d1348 – Medium article on how to solve InputMethodManager related leaks