Google is committed to advancing racial equity for Black communities. See how.

Advanced Android 04.2: Memory Profiler tool

This codelab is part of the Advanced Android Development training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.

For complete details about the course, see the Advanced Android Development overview.

Introduction

All processes, services, and apps require memory to store their instructions and data. As your app runs, it allocates memory for objects and processes in its assigned memory heap. This heap has a limited but somewhat flexible size. The Android system manages this limited resource for you by increasing or decreasing allocatable memory size. The system also frees memory for reuse by removing objects that are no longer used. If your app uses more memory than the system can make available, the system can terminate the app, or the app may crash.

  • Memory allocation is the process of reserving memory for your app's objects and processes.
  • Garbage collection is an automatic process where the system frees space in a computer's memory by removing data that is no longer required, or no longer in use.

Android provides a managed memory environment. When the system determines that your app is no longer using some objects, the garbage collector releases the unused memory back to the heap. How Android finds unused memory is constantly being improved, but on all Android versions, the system must at some point briefly pause your code. Most of the time, the pauses are imperceptible. However, if your app allocates memory faster than the system can collect unused memory, your app might be delayed while the collector frees memory. The delay could cause your app to skip frames and look slow.

Even if your app doesn't seem slow, if your app leaks memory, it can retain that memory even while in the background. This behavior can slow the rest of the system's memory performance by forcing unnecessary garbage-collection events. Eventually, the system is forced to stop your app process to reclaim the memory. When the user returns to your app, the app must restart completely.

To help prevent these problems, use the Memory Profiler tool to do the following:

  • Look for undesirable memory-allocation patterns in the timeline. These patterns might be causing performance problems.
  • Dump the Java heap to see which objects are using memory at any given time. Dumping the heap several times over an extended period can help you identify memory leaks.
  • Record memory allocations during normal and extreme user interactions. Use this information to identify where your code is allocating too many or large objects in a short time, or where your code is not freeing the allocating objects and causing a memory leak.

For information about programming practices that can reduce your app's memory use, read Manage Your App's Memory.

What you should already know

You should be able to:

  • Create apps with Android Studio and run them on a mobile device.

What you'll learn

  • Use Memory Profiler to collect data about your app.
  • View Memory Profiler reports.
  • Dump the Java heap and inspect it.
  • Record memory allocation data for your app.

What you'll do

  • Run Memory Profiler and generate, save, and inspect data.
  • You will run the LargeImages app from a previous practical, using the Memory Profiler.
  • You will run the MemoryOverload app, which creates thousands of views, eventually using up all available memory.

Screenshot of the MemoryOverload demo app, which creates thousands of views

Android Profiler is a set of tools that provide real-time information about your app, such as memory allocation and network usage. You can capture and view data as your app runs, and store data in a file that you can analyze in various viewers.

In this practical, you learn the basics of using Memory Profiler to track down performance problems and crashes related to your app's memory usage.

If you did any of the previous performance tools practicals, your environment is already set up for debugging with the Android Profiler. Otherwise, see the Prerequisites.

1.1 Start the Memory Profiler tool with the LargeImages app

  1. Open the LargeImages app in Android Studio.
  2. Run LargeImages on a device with Developer options and USB Debugging enabled. If you connect a device over USB but don't see the device listed, ensure that you have enabled USB debugging on the device.

For the next steps, use the screenshot below as a reference.

  1. To open the Android Profiler, at the bottom of Android Studio click the Android Profiler tab (shown as 1 in the screenshot).
  2. Select your device and app, if they are not automatically selected (2 in the screenshot).

The Memory graph starts to display. The graph shows real-time memory use (3). The x-axis shows time elapsed, and the y-axis shows the amount of memory used by your app (4). 3. In the app, swap the images to see the Memory graph change.

(1) Start Android Profiler. (2) Select your device and app. (3) The Memory graph starts to display, showing amount of memory over time (4).

  1. Click in the Memory graph, and the graph expands and separates into memory types. Each memory type (such as Java, Native, and Graphics) is indicated with a different color in a stacked graph. Check the key along the top of the graph to match colors and memory types.

Memory Profiler tool showing types of memory allocated

1.2 Read about the Memory Profiler tool

Familiarize yourself with the Memory Profiler user interface, panes, and features with the help of the annotated screenshot below. Not all of these tools are open when you start Memory Profiler.

Memory Profiler, with results from a memory allocation recording. The screenshot shows all panes opened.

The Memory Profiler panes and features that you use in this practical are shown in the screenshot, as follows:

  • (1) Force garbage collection. Small Trash icons in the graph indicate garbage-collection events that you or the system triggered.
  • (2) Capture a heap dump and display its contents.
  • (3) Record memory allocations and display the recorded data.
  • (4) The highlighted portion of the graph shows allocations that have been recorded. The purple dots above the graph indicate user actions.
  • (5) Allocation-recording and heap-dump results appear in a pane below the timeline. This example shows the memory allocation results during the time indicated in the timeline.
  • (5 and 6) When you view either a heap dump or memory allocations, you can select a class name from this list (5) to view the list of instances on the right (6).
  • (7) Click an instance to open an additional pane. When you are viewing the allocation record, the additional pane shows the stack trace for where that memory was allocated. When you are viewing the heap dump, the additional pane shows the remaining references to that object.

See the Memory Profiler documentation for a full list of controls and features.

1.3 Run Memory Profiler for the MemoryOverload app

A memory leak is when an app allocates memory that is never freed, even after the memory is no longer needed. A memory leak can happen when an app allocates many objects and does not free unused or dereferenced objects. Memory leaks can slow down an app or in the worst case, eventually make the app crash. Finding and fixing memory leaks is a lot easier if you have a tool that shows you what's happening with the memory that your app is using.

To demonstrate a memory leak, the MemoryOverload app creates and loads hundreds of TextView objects at the tap of a button. When you run the app and monitor it with Memory Profiler, you see a graph that shows more and more memory being allocated. Eventually, the app runs out of memory and crashes.

  1. Download the MemoryOverload app.
  2. Run the app.
  3. In Android Studio, open the Android Profiler. Click in the Memory graph to see the detail view for Memory Profiler.
  4. In the app, tap the floating action button (+). Wait until the app is done adding the views to the screen. This may take a while. In Memory Profiler, observe how the app is using more memory as views are added.
  5. Tap the + button a few more times. Your app will generate a graph similar to the one shown below. The graph shows more and more memory used and few, small, or no garbage-collection events. This allocation-graph pattern can indicate a memory leak. (The graph can look very different for different devices.)

Pattern that can indicate a memory leak

  1. Keep adding views until the app crashes and shows an Application Not Responding (ANR) dialog. Logcat displays a message like this one:
 03-24 13:05:05.226 10057-10057/com.example.android.memoryoverload A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 10057 (.memoryoverload)

SIGABRT is the signal to initiate abort() and is usually called by library functions that detect an internal error or some seriously broken constraint.

  1. After overloading and crashing your device, it is a good idea to remove the app from your device and restart your device.

One fix for the MemoryOverload app would be to not create views that are not visible on the screen. A second solution would be to combine views. Instead of creating a view for each rectangle in a row, you could create a patterned background of rectangles and show multiple rectangles in one view.

2.1 Dump the Java (app) heap

  1. Run the MemoryOverload app.
  2. In Android Studio, open the Android Profiler.
  3. Click the Memory graph to fill the Android Profiler pane with the detailed view.
  4. In the MemoryOverload app, tap the floating action button (+) once to add a set of views. Wait for the row of views to appear.
  5. In Android Studio, click the Dump Java Heap button Dump Java Heap button to capture the app heap into a file and open the list of classes. This can take a long time. The Heap Dump pane will open after the heap dump is complete.

The Dump Java Heap button in the Android Profiler pane

2.2 Inspect the dumped heap

Do the following to open all the information panes, then refer to the screenshot annotations for an explanation of each pane.

  1. In the Heap Dump pane (1), find and click the TextView class. This opens an Instance View pane.
  2. In the Instance View pane (2), click one of the TextView instances. This opens a References pane (3). Your screen should now look similar to the screenshot below.

Heap dump of the MemoryOverload app with detail panes open

The Heap Dump pane (1) shows all the classes related to your app, as they are represented on the heap. The columns give you size information for all the objects of this class. Click a column header to sort by that metric.

  • Allocation Count: Number of instances of this class that are allocated.
  • Shallow Size: Total size of all instances of this class.
  • Retained Size: Size of memory that all instances of this class are dominating.

After you click the floating action button (+) in the MemoryOverload app, you see a large number of TextView instances on the screen. Corresponding allocations are recorded on the graph and in the allocation count for the TextView class.

The Instance View pane (2) lists all the instances of the selected TextView class that are on the heap. The columns are as follows.

  • Depth: Shortest number of hops from any garbage-collection root to the selected instance.
  • Shallow Size: Size of this instance, in bytes.
  • Retained Size: Total size of memory being retained due to all instances of this class, in bytes.

The References pane (3) shows all the references to the selected instance. For example, in the MemoryOverload app, all the views are created and added to the view hierarchy. When you are debugging an app, look for classes and instances that should not be there, and then check their references.

For example, if you are offloading work to another thread, it is possible that references to views or activities remain after an Activity has been restarted, leaking memory on every configuration change. Look for long-lived references to Activity, Context, View, Drawable, and other objects that might hold a reference to the Activity or Context container.

Right-click a class or instance and select Jump to Source. This opens the source code, and you can inspect it for potential issues.

Click the Export button Export heap dump button at the top of the Heap Dump pane to export your snapshot of the Java heap to an Android-specific Heap/CPU Profiling file in HPROF format. HPROF is a binary heap-dump format originally supported by J2SE. See HPROF Viewer and Analyzer if you want to dig deeper.

See Memory Profiler, Processes and Threads, and Manage Your App's Memory.

Dumping the heap gives you a snapshot of the allocated memory at a specific point in time. Recording allocations shows you how memory is being allocated over a period of time.

3.1 Record allocations

  1. Run the MemoryOverload app.
  2. In Android Studio, open the Android Profiler.
  3. Click the Memory graph to fill the Android Profiler pane with the detailed view.
  4. Click the Record Memory Allocations button The Record Memory Allocations button.

The Record Memory Allocations button

  1. On your device with the MemoryOverload app running, tap the floating action button (+) to add a set of views.
  2. Wait only a few seconds, then click the Record Memory Allocations button again. The button is now a black square The button to stop recording memory allocations indicating that clicking it will pause the recording. Don't wait too long to pause the recording, because the recorded files can get large.

3.2 Inspect recorded allocations

Refer to the screenshot below for the next steps.

  1. The Memory graph indicates which portion was recorded (1). Select the recorded portion, if necessary. You can record more than one section of the graph and switch between them.
  2. As in the previous task, the Heap Dump pane (2) shows the recorded data.
  3. Click a class name to see instances allocated during this period of time (3). As in the previous task, there should be many instances of the TextView class.
  4. Click an instance to see its Call Stack (4).
  5. At the top of the Call Stack (which is actually the bottom...) is the method call in your code that initiated creation of this instance. In this case, the method is addRowOfTextViews().

Click addRowOfTextViews to locate this call in your code (5).

Recorded allocations of the MemoryOverload app with detail panes open

To export the recordings to an hprof file (for heaps) or an alloc file (for allocations), click the Export button Heap window export button in the top-left corner of the Heap Dump or Allocations pane. Load the file into Android Studio later for exploration.

Android Studio project: MemoryOverload

  • Use Memory Profiler to observe how your app uses memory over time. Look for patterns that indicate memory leaks.
  • Use Java heap dumps to identify which classes allocate large amounts of memory.
  • Record allocations over time to observe how apps allocate memory and where in your code the allocation is happening.

The related concept documentation is in 4.2 Memory.

Android developer documentation:

The Android Performance Patterns video series show older tools but the principles all apply:

This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:

  • Assign homework if required.
  • Communicate to students how to submit homework assignments.
  • Grade the homework assignments.

Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.

If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.

Build and run an app

  1. Use the app that you created for the homework assignment in the 4.1 Part A: Profile GPU Rendering tool codelab.
  2. Run Memory Profiler on the app.
  3. Take a screenshot of the Memory graph to submit with your observations.
  4. On the screenshot, identify portions of the graph that are relevant to your app and reflect on them.
  5. Change your app in a way that noticeably changes the graph. Take a screenshot and submit it with an explanation of the changes.

Answer these questions

Question 1

What tools are available in Android Studio for measuring memory performance?

  • Systrace
  • Heap dumps
  • Debug GPU Overdraw
  • Memory Profiler

Question 2

Looking at this Memory Monitor graph, which of the following statements is true?

32c08258dd54a5a6.png

  • The app is allocating an increasing amount of memory, and you should investigate for possible memory leaks.
  • The app will run out of memory and crash.
  • The app will slow down over time because less memory is available.
  • More garbage collection events will happen, resulting in a slower app.

Question 3

Select all answers that describe features and benefits of a heap dump:

  • A heap dump is a snapshot of the allocated memory at a specific time.
  • You can look at a static snapshot of allocated memory.
  • You can dump the Java heap to see which objects are using up memory at any given time.
  • Heap dumps show how memory is allocated over time.
  • Doing several heap dumps over an extended period can help you identify memory leaks.

Question 4

What are the benefits of recording memory allocations? Select up to four.

  • You can track allocations and deallocations over time.
  • You can track how much space files take up on each partition.
  • You can inspect the call stack and find out where in your code an allocation was made.
  • You can track down which objects might be responsible for memory leaks.
  • You can record memory allocations during normal and extreme user interactions. This recording lets you identify where your code is allocating too many objects in a short time, or allocating objects that leak memory.

Submit your findings for grading

No app to submit for this homework assignment.

Submit the annotated screenshot that you took of the Memory graph, along with your observations.

Guidance for graders

Check that:

  • Student submitted annotated screenshot of the app with Memory Profiler turned on
  • Student submitted comments relating the graph to their app.
  • Student submitted a second, different screenshot, along with an explanation of what they did to cause this change, as well as reflections on the change.

To see all the codelabs in the Advanced Android Development training course, visit the Advanced Android Development codelabs landing page.