[This post is by Patrick Dubroy, an Android engineer who writes about programming, usability, and interaction on hispersonal blog.—TimBray]

The Dalvik runtime may be garbage-collected, but that doesn't mean you can ignore memory management. You should be especially mindful of memory usage on mobile devices, where memory is more constrained. In this article, we're going to take a look at some of the memory profiling tools in the Android SDK that can help you trim your application's memory usage.

Some memory usage problems are obvious. For example, if your app leaks memory every time the user touches the screen, it will probably trigger anOutOfMemoryErroreventually and crash your app. Other problems are more subtle, and may just degrade the performance of both your app (as garbage collections are more frequent and take longer) and the entire system.

Tools of the trade

The Android SDK provides two main ways of profiling the memory usage of an app: theAllocation Trackertab in DDMS, and heap dumps. The Allocation Tracker is useful when you want to get a sense of what kinds of allocation are happening over a given time period, but it doesn't give you any information about the overall state of your application's heap. For more information about the Allocation Tracker, see the article onTracking Memory Allocations. The rest of this article will focus on heap dumps, which are a more powerful memory analysis tool.

A heap dump is a snapshot of an application's heap, which is stored in a binary format called HPROF. Dalvik uses a format that is similar, but not identical, to theHPROF tool in Java. There are a few ways to generate a heap dump of a running Android app. One way is to use theDump HPROF filebutton in DDMS. If you need to be more precise about when the dump is created, you can also create a heap dump programmatically by using theandroid.os.Debug.dumpHprofData()function.

To analyze a heap dump, you can use a standard tool likejhator theEclipse Memory Analyzer (MAT). However, first you'll need to convert the .hprof file from the Dalvik format to the J2SE HPROF format. You can do this using thehprof-convtool provided in the Android SDK. For example:

hprof-conv dump.hprof converted-dump.hprof

Example: Debugging a memory leak

In the Dalvik runtime, the programmer doesn't explicitly allocate and free memory, so you can't really leak memory like you can in languages like C and C++. A "memory leak" in your code is when you keep a reference to an object that is no longer needed. Sometimes a single reference can prevent a large set of objects from being garbage collected.

Let's walk through an example using theHoneycomb Gallery sample appfrom the Android SDK. It's a simple photo gallery application that demonstrates how to use some of the new Honeycomb APIs. (To build and download the sample code, see theinstructions.) We're going to deliberately add a memory leak to this app in order to demonstrate how it could be debugged.

Imagine that we want to modify this app to pull images from the network. In order to make it more responsive, we might decide to implement a cache which holds recently-viewed images. We can do that by making a few small changes to ContentFragment.java. At the top of the class, let's add a new static variable:

private static HashMap<String,Bitmap> sBitmapCache = new HashMap<String,Bitmap>();

This is where we'll cache the Bitmaps that we load. Now we can change theupdateContentAndRecycleBitmap()method to check the cache before loading, and to add Bitmaps to the cache after they're loaded.

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); }

I've deliberately introduced a memory leak here: we add Bitmaps to the cache without ever removing them. In a real app, we'd probably want to limit the size of the cache in some way.

Examining heap usage in DDMS

The Dalvik Debug Monitor Server (DDMS) is one of the primary Android debugging tools. DDMS is part of theADT Eclipse plug-in, and a standalone version can also be found in thetools/directory of the Android SDK. For more information on DDMS, seeUsing DDMS.

Let's use DDMS to examine the heap usage of this app. You can start up DDMS in one of two ways:

  • from Eclipse: clickWindow > Open Perspective > Other... > DDMS
  • or from the command line: runddms(or./ddmson Mac/Linux) in thetools/directory

Select the processcom.example.android.hcgalleryin the left pane, and then click theShow heap updatesbutton in the toolbar. Then, switch to theVM Heaptab in DDMS. It shows some basic stats about our heap memory usage, updated after every GC. To see the first update, click theCause GCbutton.

We can see that our live set (theAllocatedcolumn) is a little over 8MB. Now flip through the photos, and watch that number go up. Since there are only 13 photos in this app, the amount of memory we leak is bounded. In some ways, this is the worst kind of leak to have, because we never get anOutOfMemoryErrorindicating that we are leaking.

Creating a heap dump

Let's use a heap dump to track down the problem. Click theDump HPROF filebutton in the DDMS toolbar, choose where you want to save the file, and then runhprof-convon it. In this example, I'll be using the standalone version of MAT (version 1.0.1), available from theMAT download site.

If you're running ADT (which includes a plug-in version of DDMS) and have MAT installed in Eclipse as well, clicking the “dump HPROF” button will automatically do the conversion (using hprof-conv) and open the converted hprof file into Eclipse (which will be opened by MAT).

Analyzing heap dumps using MAT

Start up MAT and load the converted HPROF file we just created. MAT is a powerful tool, and it's beyond the scope of this article to explain all it's features, so I'm just going to show you one way you can use it to detect a leak: the Histogram view. The Histogram view shows a list of classes sortable by the number of instances, theshallow heap(total amount of memory used by all instances), or theretained heap(total amount of memory kept alive by all instances, including other objects that they have references to).

If we sort by shallow heap, we can see that instances ofbyte[]are at the top. As of Android 3.0 (Honeycomb), the pixel data for Bitmap objects is stored in byte arrays (previously it was not stored in the Dalvik heap), and based on the size of these objects, it's a safe bet that they are the backing memory for our leaked bitmaps.

Right-click on thebyte[]class and selectList Objects > with incoming references. This produces a list of all byte arrays in the heap, which we can sort based on Shallow Heap usage.

Pick one of the big objects, and drill down on it. This will show you the path from the root set to the object -- the chain of references that keeps this object alive. Lo and behold, there's our bitmap cache!

MAT can't tell us for sure that this is a leak, because it doesn't know whether these objects are needed or not -- only the programmer can do that. In this case, the cache is using a large amount of memory relative to the rest of the application, so we might consider limiting the size of the cache.

Comparing heap dumps with MAT

When debugging memory leaks, sometimes it's useful to compare the heap state at two different points in time. To do this, you'll need to create two separate HPROF files (don't forget to convert them usinghprof-conv).

Here's how you can compare two heap dumps in MAT (it's a little complicated):

  1. Open the first HPROF file (usingFile > Open Heap Dump).
  2. Open the Histogram view.
  3. In the Navigation History view (useWindow > Navigation Historyif it's not visible), right click onhistogramand selectAdd to Compare Basket.
  4. Open the second HPROF file and repeat steps 2 and 3.
  5. Switch to the Compare Basket view, and clickCompare the Results(the red "!" icon in the top right corner of the view).

Conclusion

In this article, I've shown how the Allocation Tracker and heap dumps can give you get a better sense of your application's memory usage. I also showed how The Eclipse Memory Analyzer (MAT) can help you track down memory leaks in your app. MAT is a powerful tool, and I've only scratched the surface of what you can do with it. If you'd like to learn more, I recommend reading some of these articles:

  • Memory Analyzer News: The official blog of the Eclipse MAT project
  • Markus Kohler's Java Performance blog has many helpful articles, includingAnalysing the Memory Usage of Android Applications with the Eclipse Memory Analyzerand10 Useful Tips for the Eclipse Memory Analyzer.

转自:http://android-developers.blogspot.hk/2011/03/memory-analysis-for-android.html

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. 屏幕适配备忘录
  2. 网页加速之Link prefetching
  3. [WebView学习之二]:使用Web Apps 支持不
  4. Android(安卓)菜单和对话框等
  5. Android(安卓)SimpleArrayMap源码解析
  6. Android(安卓)在低版本sdk中没有getSuppo
  7. 《老罗Android》监听电量变化、Broadcast
  8. Android(安卓)架构组件之 Lifecycle 使用
  9. Java Nested class
  10. [Android][AlarmManager]