This Blog is all about memory management in Android. It provides information about how you can analyze & reduce memory usage while developing an Android app.

Memory management is a complex field of computer science and there are many techniques being developed to make it more efficient. This guide is designed to introduce you to some of the basic memory management issues that programmers face.

Memory Management in Android

Android is a Linux based operating system. It uses native open source C libraries which power Linux machines. All the basic operating system operations like I/O, memory management and so on are handled by the Linux kernel. Like Java and .NET, Android uses its own run time and virtual machine to manage application memory. Unlike either of these frameworks, the Android run time also manages the lifetime processes.

Each Android application runs in a separate process within its own Dalvik instance, relinquishing all responsibility for memory and process management to the Android run time, which stops and kills processes, necessary to manage resources. Dalvik is an open source, register-based virtual machine (VM) that is part of the Android Operating System. The Dalvik VM executes files in the Dalvik Executable (.dex) format. Resources are simple files in xml format.

Dalvik and the Android run time sit on top of a Linux kernel that handles low-level hardware interaction including drivers and memory management, while a set of APIs provide access to all the under-lying services, features and hardware.

A systematic examination and evaluation of data or information is very important so that we can manage the available memory in an effective way. For this we have DDMS in Android Studio IDE, using which we can analyze the memory being utilized. (IDE is Integrated Development Environment which provides the platform for developing an app in Android)

DDMS

Let us understand DDMS now. Android studio includes a debugging tool called the Dalvik Debug Monitor Service (DDMS). DDMS provides services like screen capture on the device, threading, heap information on the device, logcat, processes, incoming calls, SMS checking, location, data spoofing, and many other things related to testing your Android application.

Features of DDMS

DDMS connects the IDE to the applications running on the device. On Android, every application runs in its own process, each of which hosts its own virtual machine (VM). And each process listens for a debugger on a different port.

When it starts, DDMS connects to ADB (Android Debug Bridge which is a command-line utility included with Google’s Android SDK.). An Android Debugger is used for debugging the Android app and starts a device monitoring service between the two. This will notify DDMS when a device is connected or disconnected. When a device is connected, a VM monitoring service is created between ADB and DDMS, which will notify DDMS when a VM on the device is started or terminated.

Let’s analyze the above explained memory utilization with a simple example. Android applications are limited to 16 MB of heaped memory. Usually a lot of memory is used for a phone and very little memory is left for what some developers want to achieve.

Even if you do not plan on using all of this memory, you should use memory as little as possible to let other applications run without getting them killed. The more applications Android can keep in memory, the faster it will be for the user to switch between his apps.

As a developer, we often run into memory leaks issues in Android applications. Most of the time the memory leak occurs due to the same mistake: keeping a long-lived reference to a Context. On Android, a Context is used for many operations, but mostly to load and access resources. This is why all the widgets receive a Context parameter in their constructor.

In a regular Android application, you usually have two kinds of Context – Activity and Application.

It’s usually Activity that the developer passes to classes and methods that need a Context as shown in Figure below. (An activity represents a single screen with a user interface just like window or frame of Java)

@Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad");setContentView(label); }

Therefore, if you leak the Context (“leak” meaning you keep a reference to it thus preventing the Garbage Collector from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you’re not careful.This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources.

When the screen’s orientation changes, the system by default will destroy the current activity and create a new one while preserving its state. In doing so, Android will reload the application’s UI from the resources.

Now imagine you wrote an application with a large bitmap that you don’t want to load on every rotation. The easiest way to keep it around and reload it on every rotation is to keep in a static field as shown in Figure below:

private static Drawable sBackground; @Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); }

In the code snippet above, the Drawable has a reference to the TextView which itself has a reference to the Activity (the Context) which in turns has references to almost everything (depending on your code.)This code leaks the Activity created upon the first screen orientation change.

This example is one of the simplest cases of leaking the Context and you can see how we worked around it in the Main Screen of the app.

The example above showed the case of a static reference but inner classes and their implicit reference to the outer class can be equally dangerous. So we can come up with a second solution.

The second solution is to use the Application Context. This Context will live as long as your application is alive and does not depend on the activities life cycle. If you plan on keeping long-lived objects that need a Context, remember the Application object. You can obtain it easily by calling, Context.getApplicationContext() or Activity.getApplication().

Thus having discussed both Activity and Application context let just discuss some points to remember so as to avoid memory leaks:

Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself).

Try using the context-application instead of a context-activity.

Avoid non-static inner classes in an activity if you are not controlling their life cycle. Use a static inner class and make a weak reference to the activity inside.

A garbage collector is not an insurance against memory leaks which occurs when there is either too littlememory available or your memory is too fragmented to allocate a large object.

The Dalvik Runtime is a Garbage-Collector. So Android operating system manages memory automatically in some ways. But you can’t ignore memory management all together. As a developer, you should manage memory at the time of developing an application. For Memory Management in Android Apps, We have some memory profiling tools in the Android SDK (Software Development Kit).

The solution to managing memory in an Android device is through Profiling Tools which we will discuss now.

Android Profiling Tools

Android Profiling Tool will help you in managing your memory on the Android device. The Android SDK provides two ways of profiling app memory:

Using Allocation Tracker Using Heap Dump

Using Allocation Tracker:

Allocation Tracker records each memory allocation that your application performs during the profiling cycle. The Allocation Tracker is useful when you want to find out which type of memory allocation is taking place. But it does not give you any information about the application’s heap which is the memory set aside for dynamic memory allocation.

The Allocation Tracker displays the memory allocation for the selected process. It shows the specific objects that are being allocated along with the thread, method and the line code that allocated them.

DDMS provides a feature to track objects that are being allocated to memory and to see which classes and threads are allocating the objects. This allows you to track where the objects are being allocated in real time, when you perform certain actions in your application. This data is valuable for measuring memory usage that can otherwise affect application performance.

Steps for starting Allocation Tracker in Android DDMS

Install your app in Android emulator or device. Click on Android button available at the bottom of the Android Studio.

Start allocation tracking.

Play around with app for some time.

Stop allocation tracking.

Refer to the Figure below:

After a few seconds, a pane with your recorded data opens.

Heap Dumps

A Heap Dump is a snapshot of an application’s heap, which is stored in a binary format called HPROF. The Dalvik virtual machine can produce a complete dump of the contents of the virtual heap. This is very useful for debugging memory usage and looking for memory leaks.

Steps for checking memory allocation using heap

For checking App Heap and memory allocation in Android Studio, first, you have to install MAT which can be downloaded from this link – download The Eclipse Memory Analyser Tooling (MAT) is a set of plug-ins for the Eclipse IDE which provides tools to analyze heap dumps from Java application and to identify memory problems in the application. This helps the developer to find memory leaks and high memory consumption issues.

After installing MAT, follow below mentioned steps:

In Android Studio open Android Device Monitor (Tools -> Android -> Android Device Monitor). In the top left side under Devices select your project process/ package name & click Update Heap above the process list.

3. In the right-side panel, select the Heap tab.

4. Click on Cause GC icon to get memory allocation results.

5. Click on Dump HPROF file above the process list & save it. Here it’s been saved in Videos folder.

6. Then run the Command prompt and point out the Android-SDK directory.

7. Find out where hprof-conv is located. Here you can assume that it is in C directory. Then finally run this command by referring this document to convert this file format to read it in MAT.

Microsoft Windows [Version 6.3.9600] (c) 2013 Microsoft Corporation. All rights reserved. C:\Users\admin>cd C:\Users\Tools\adt-bundle-windows-x86_64-20140702\adt-bundle-windows-x86_64-20140702\sdk\platform-tools C:\Users\Tools\adt-bundle-windows-x86_64-20140702\adt-bundle-windows-x86_64-20140702\sdk\platform-tools>hprof-conv "C:\Users\admin\Videos\memoryleak.acadgild.com.myapplication.hprof" "C:\Users\admin\Videos\leakage.hprof”

Now your file will convert to leakage.hprof. Check this file and open it in MAT (Eclipse Memory Analyzer) as shown in Figure below.







Real Time Example of Memory Leak

Below example will help you know how to find memory leaks that you can fix. There are some steps following which you can find the leaks in an easy way:

Create Android Studio Project & modify MainActivity.java

package com.acadgild.memoryleak; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity{ static MemoryLeakyCheck checkLeak=null; class MemoryLeakyCheck{ } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(checkLeak==null){ checkLeak=new MemoryLeakyCheck(); } } }

2. Start your Android Virtual device & run your application in debug mode. Click yes to enable ADB integration to launch debugging.

3. Follow steps correctly for checking memory allocation using Heap. If you follow the steps correctly you will be able to find the below screen shot:

4. Select “Leak Suspects Report” & click on Finish. You should be able to see the details of leak suspects along with the problem statement as shown below:

Problem Suspect 1

Problem Suspect 2

Problem Suspect 3

5. Create a Histogram from a given set of arbitrary objects.

6. Click on the Shallow Heap title bar to sort data in ascending order.

7. Right Click on byte[] -> List Objects -> with incoming references

You should be able to view below screen shot as outcome:

8. Open Object Query Language Studio to execute statements.

Execute below query to find leaks:

select * from memoryleak.acadgild.com.myapplication.MainActivity

Then click F5 to run the query where you find the results as shown in Figure below:

9. Right click on the result that comes up and go to Path to GC Roots -> Exclude weak references

10. Find Memory Leak Objects & fix it through code.

11. Now you know that memory leak happened due to static variable “checkLeak”. So remove static keyword for this variable.

Your code should look like Figure below: