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.

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:

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:

What you'll learn

What you'll do

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.


  4. 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.

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.

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

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.)

  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 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.

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.

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.

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.

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 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 .

  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 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).

To export the recordings to an hprof file (for heaps) or an alloc file (for allocations), click the 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

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:

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?

Question 2

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

Question 3

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

Question 4

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

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:

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