Dalvik has a garbage collector, but that does not mean that you can ignore memory management. Quite the contrary - you need to be especially careful when using memory, which, as you know, is limited on mobile devices. In this article, we will look at tools that significantly help monitor how an application uses memory.
Some problems from overuse of memory are quite obvious. For example, in your application a memory leak constantly occurs when the user touches the screen, then this eventually may cause
OutOfMemoryError , and the application will crash and close. Other problems that are more subtle than this may lead to a general decline in the performance of the application and the system as a whole (because the garbage collector will be called more frequently and for a longer time).
Instruments
The Android SDK provides two primary devices for profiling application memory usage: the Allocation Tracker tab in
DDMS and heap dumps. Allocation Tracker can be useful when you want to learn about memory usage in a specific period of time, as it does not provide information about the full state of the heap that is allocated for an application. For more information about Allocation Tracker, see the article
Tracking Memory Allocations . The rest of this article will be devoted to the study of heap dumps, as this is a more powerful tool.
')
A heap dump is a snapshot of the entire heap of an application that is stored in a binary file, HPROF format. Dalvik uses a format that is similar to the one used by the
HPROF tool in Java, but is not exactly the same.
There are several ways to create a heap dump of an running Android application. The first is to use the
Dump HPROF file button in DDMS. If you need to choose the moment of creating the dump more precisely, you can create it programmatically using the
android.os.Debug.dumpHprofData () method.
For analysis, you can use the standard
jhat tool or
Eclipse Memory Analyzer (MAT) . However, you first need to convert the .hprof file from Dalvik format to J2SE HPROF format. To do this, use the
hprof-conv utility, which comes with the Android SDK:
hprof-conv dump.hprof converted-dump.hprof
Example: Debugging Memory Leaks
In Dalvik, a programmer does not explicitly place anything in free memory, so there may be leaks, as in C and C ++. By "memory leak" is usually understood a situation in which you continue to refer to an object that is no longer needed. Sometimes, a single reference can prevent a call to the garbage collector to remove a large set of objects.
Let's look at the
Honeycomb Gallery sample app from the Android SDK. This is a simple photo gallery that demonstrates the use of some new API methods in Honeycomb. We will now intentionally create a memory leak to demonstrate the debugging method.
Imagine that we want an application to receive images over the network. To make it more responsive to the user, it may be worthwhile to implement a cache for storing recently viewed images. We can do this by making some changes to
ContentFragment.java . At the beginning of the class, declare and initialize a new variable:
private static HashMap<String,Bitmap> sBitmapCache = new HashMap<String,Bitmap>();
In this display, we will cache the loaded Bitmap's. Now you can change the
updateContentAndRecycleBitmap () method to check the cache before loading and add Bitmap to the cache after loading:
void updateContentAndRecycleBitmap(int category, int position) { if (mCurrentActionMode != null) { mCurrentActionMode.finish(); } // Get the bitmap that needs to be drawn and update the ImageView. // Check if the Bitmap is already in the cache String bitmapId = "" + category + "." + position; mBitmap = sBitmapCache.get(bitmapId); if (mBitmap == null) { // It's not in the cache, so load the Bitmap and add it to the cache. // DANGER! We add items to this cache without ever removing any. mBitmap = Directory.getCategory(category).getEntry(position) .getBitmap(getResources()); sBitmapCache.put(bitmapId, mBitmap); } ((ImageView) getView().findViewById(R.id.image)).setImageBitmap(mBitmap); }
Here, I deliberately created a memory leak: Bitmaps are added to the cache, but not removed from it. In a real application, it is obvious that the cache size needs to be limited.
Heap Examination with DDMS
Dalvik Debug Monitor Server (DDMS) is one of the main debugging tools in Android. It is part of the
ADT plug-in to the Eclipse development environment, and can also be found in the
tools / folder of your Android SDK. For more information, see
Using DDMS .
Let's use DDMS to analyze the use of the heap by our application. You can run DDMS in two ways:
- From Eclipse: Window -> Open Perspective -> Other ...> DDMS
- From the command line: run ddms (or ./ddms on Mac / Linux) in the tools / folder
Select the
com.example.android.hcgallery process in the left pane and click on the
Show heap updates button on the toolbar. Then switch to the
VM Heap VM tab in DDMS. You will see some basic heap usage information that will be updated each time the garbage collector is called. To see the first update, click on the
Cause GC button.
You can see that “live” objects occupy a little less than 8Mb in memory (see the
Allocated column). Now scroll through the photos, and you can see how this number is increasing. Since the application has only 13 photos, the memory leak is limited. In a sense, this is the worst case that can happen, so
OutOfMemoryError will never be
here .
Creating a heap dump
Click on the
Dump HPROF file button in the DDMS toolbar, select where to save the file, and convert it using the
hprof-conv utility. In this example, we will use a separate version of MAT (1.0.1), it can be downloaded
here .
If you use Eclipse, with MAT installed, then after pressing the “dump HPROF” button, the file is automatically converted and opened in the Ecilpse window.
Heap dump analysis using MAT
Run MAT and download the HPROF file that you just created. MAT is a powerful utility, and an explanation of all its features outside of this topic, so I will explain only one of the methods of how to determine the leakage - using the Histogram view. In this view, you can see a list of classes sorted by the number of instances, shallow heap (total memory size occupied by instances), or retained heap (total memory occupied by instances and the objects they refer to).
If you sort by
shallow heap , you can see that at the top is the number of byte [] instances. In Android 3.0, Bitmaps are represented as arrays of bytes, the size of which depends on the size of the Bitmap. That is, it is clear that they represent the memory that deals with our bitmaps. Right-click on the byte [] class and select List Objects> with incoming references. You will see a list of all the arrays from the bytes located on the heap.
Select one of the large objects and expand it. As a result, you will see the entire chain of links, which is formed due to this object. Here it is - our cache for Bitmap!
MAT cannot give accurate information whether this is a leak, as it does not know whether these objects are needed. Only the programmer knows the answer. In our case, the cache is very large compared to the entire application, so it would be logical to limit its size.
Comparing Heap Dumps with MAT
When debugging memory leaks, it is useful to compare the state of the heap at different times. To do this, create two HPROF files (don't forget to convert them with the
hprof-conv utility).
Here is how you can compare these two files:
- Open the first file ( File> Open Heap Dump ).
- Open histogram view.
- In the form of a navigation history (Window> Navigation History), right-click on histogram and select Add to Compare Basket .
- Open the second file and repeat steps 2 and 3.
- Switch to the Compare Basket view, and click Compare the Results (the red exclamation mark icon in the upper right corner)
Conclusion
In this article, I showed how Allocation Tracker and heap dumps can help you analyze memory usage. I also showed how MAT helps track down memory leaks in an application. If you want to learn more about MAT, you can read the following articles: