Memory leaks can happen, despite the prevalence of garbage collection in modern programming languages. They can be introduced in different ways in Android apps, but one of the most common is when using native C or C++ code. When leaks make themselves known, it can range from subtle to explosive, anywhere from mild but continuous degradation in performance to outright crashes.
What is a Memory Leak?
A memory leak happens when memory is allocated but never freed. This can happen when an application or library allocates a chunk (or several chunks) of memory to use while it’s running. Since the operating system will reclaim the memory once the application ends, sometimes the application or library doesn't bother to free the memory. However, while the application continues to run, that memory will remain allocated and unusable.
When left unchecked, memory leaks can cause severe performance problems. Extreme cases will cause the program to crash in a matter of minutes. Other times the leaks grow more slowly and it take days or weeks for the application to run out of memory. During this time, performance of the system may suffer as the app continues to hoard memory.
Preventing and Reducing Memory Leaks
The most common technique to reducing memory leak in C++ is to never use a naked pointer. Instead, use the smart pointers that C++11 or greater provides. If you don’t have an updated version, use the auto_ptr from pre C++-11; it’s better than nothing!
Finding Memory Leaks
How do you know if you have a memory leak? Typically, you’ll notice the aforementioned performance hits and crashes. If you can narrow down what actions in your app cause these issues, you’ll get a head start on finding your leak. Once you have an idea where and why your application is leaking memory, you can do static code analysis to check for memory not getting properly released.
If you suspect your native Android app is leaking memory, Android itself and 3rd-party tools provide little help. Various versions of Android have attempted to make it easier to find memory leaks, but the implementations have been buggy and unreliable. Luckily, Android Oreo introduces a memory allocation library that works is a bit better.
How to Find Memory Leaks on Android Oreo
First, make sure your device is running on at least Android Oreo. You will also need to use a rooted device or run your app on an emulator. From the console, run the following commands:
$ adb root
$ adb shell setprop wrap.<your.app.name> LIBC_DEBUG_MALLOC_OPTIONS=backtrace
Then start your app. You should see a message in logcat about malloc debug being enabled. If there is a specific function in your app that you suspect is leaking memory, then exercise that function as many times as you can. Let your app run until you think some memory has leaked and then run this command in the console:.
$ adb shell dumpsys meminfo --unreachable <PID_OF_YOUR_PROCESS>
This will provide a list of memory allocations that the memory allocator believes have been leaked, complete with backtraces so that you can more easily identify what execution path led to the allocation of that memory. Some of these memory blocks may be red herrings, but be patient. If memory has leaked, then it is very likely that it will be listed in the meminfo output.Note: Sometimes the meminfo command fails. Try turning it off and on again. If you have a better solution, let us know!
Tools for Other Platforms
Unfortunately, on mobile platforms the tools to find memory leaks aren't as good as they are for the desktop. Although previous versions of Android had subpar implementations for diagnosing and fixing memory leaks, the debug help provided by the Android Oreo memory allocation library is a bit better. For iOS, use the Instruments tool that comes with Xcode. (We may write an article about using Instruments to find memory leaks in the future for our iOS followers!)