The Android Memory Profiler is a tool which helps you understand the memory usage of your app. Every Android developer should understand memory management. Memory pitfalls cause many of the crashes and performance issues in Android apps.
In this tutorial you’ll learn how to track memory allocation and create heap dumps using the Android Memory Profiler.
Note: This tutorial assumes you have previous experience developing for Android in Kotlin. If you’re unfamiliar with the language, have a look at this tutorial. If you’re beginning with Android, check out some of our Getting Started and other Android tutorials.
Android Profiler, which replaces Android Monitor tools, is included in Android Studio 3.0 and later. It measures several performance aspects of an app in real-time like:
In this tutorial you’ll focus on memory analysis.
Android Memory Management
The Android virtual machine keeps track of each memory allocation in the heap. The heap is a chunk of memory where the system allocates Java/Kotlin objects.
There’s a process for reclaiming unused memory known as garbage collection. It has the following objectives:
- Find objects that nobody needs.
- Reclaim the memory used by those objects and return it to the heap.
You don’t generally request a garbage collection. Instead, the system has a running set of criteria to determine when to perform one.
To enable a multi-task environment, Android puts a limit on the heap size for each app. This size will vary depending on how much available RAM the device has. When the heap capacity is full and the system tries to allocate more memory, you could get an OutOfMemoryError.
Garbage Collection Roots
Suppose you have the following objects in memory:
The top white objects are called GC Roots. No other object in the heap references them.
To simplify things, you can think of obj9 as an activity retaining other objects: obj10, obj11 and obj12.
Suppose you’re in that activity and press back, finishing it. The system will clear the reference from obj7 to obj9:
When the system triggers the Garbage Collector, it’ll start from the GC roots. It’ll realize that obj9 and the rest of the objects retained by it, obj10, obj11 and obj12, aren’t reachable and will collect them.
Why You Should Profile Your App Memory
The system has to pause your app’s code to let the Garbage Collector do its job. Usually, this process is imperceivable.
But other times you’ll notice your app is sluggish and skipping frames. This happens when your app allocates memory faster than the system can collect it.
When you leak memory it can’t be released back to the heap. This forces unnecessary garbage collection events and slows the rest of the system. Eventually, the system may kill your app process to reclaim the memory.
To avoid these problems, you should profile your app memory.
To get started with this tutorial, click the Download Materials button at the top or bottom of the tutorial to download the starter project.
Throughout this tutorial you’ll work with TripLog app. TripLog lets the user write notes about what they are doing and feeling during a trip.
Open Android Studio 3.4.1 or later, click File ▸ New ▸ Import Project. Select the top-level project folder for the starter project you downloaded.
Alternatively, you can select Open an existing Android Studio project from the Welcome screen. Again, choose the top-level project folder for the starter project you downloaded.
Build and run TripLog to become familiar with it:
The TripLog project contains the following main files:
- MainActivity.kt contains the main screen. It’ll show all the logs here.
- DetailActivity.kt allows the user to create or view a log.
- MainApplication.kt provides dependencies for the activities: a repository and formatters.
- TripLog.kt represents the data of a log.
- Repository.kt saves and retrieves logs.
- DateFormatter.kt formats the data to show in the screens.
Using the Android Profiler
Open the Android Profiler:
You can also open it by going to View ‣ Tool Windows ‣ Profiler.
You should see the current session:
If you don’t see the session listed, press the + button and select the app.
Apply, build and run your app again.
Now, click the Memory section:
At the top, you’ll see the current activity. In this case it’s the MainActivity.
In the app, press the + button to add a new log and check the profiler:
It now shows the DetailActivity is the current activity and a small pink dot. The profiler shows these dots each time you touch the screen. Later, you’ll also see other icons, such as back or keyboard, when you press them on your device or emulator.
Below that, you can see the memory count of your app, segmented into several categories:
- Java: Memory from objects that Java/Kotlin has allocated.
- Native: Allocated memory from C/C++ code objects.
- Graphics: Memory to display pixels to the screen.
- Stack: Memory used by both native and Java stacks in your app. When your app invokes a method, a block is created in the stack memory to hold local primitive values and references to other objects in this method.
- Code: Memory used for code and resources such as dex bytecode, .so libraries and fonts.
- Others: Memory that the system doesn’t know how to categorize.
- Allocated: The number of Java/Kotlin objects your app has allocated.