HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID (PART 2 OF 2)

Woo-hoo! Now you know what is happening with your app’s memory usage when you see one of those OOM exception. But, you don’t know where to find the source. Let alone, how to fix it.

Tracking down memory issues can be a pain in the neck. Here are a few strategies that will help you as you pursue the noble craft of Android-igami.

Sample project

There are code snippets and screenshots of what I’m working on sprinkled throughout this post. These will come from a single sample project, and if you prefer to see things in their entirety before being divided into little pieces, I provided that sample project to download here.

  • Yes, it uses Eclipse. Sorry to all you cutting edge folks working with the still beta Android Studio.
  • Structure: One activity, with a fragment. You’ll see an image that turns on and off every 5 seconds.
  • We’re using a singleton manager to keep time for us, and notify the Fragment when it’s time to switch the image on or off.

For those keeping score at home, this project has one A-level memory leak: the type of leak that no developer should ever allow into their code. And I’m not going to tell you where it is. But, that’s the purpose of this experiment! So let’s take a look at where it goes wrong.

EXAMINATION 1: “UPDATE HEAP” BUTTON

  1. Open the DDMS1 Perspective in Eclipse (It should be found somewhere around the Window->Open Perspective->Other popup dialog).
  2. Highlight the process you wish to profile (most real devices will only show “debug”-signed processes, so you’d only see it on a real device if you built and installed from adb).
  3. Tap the little green “disk” icon (circled in above image), named “Update Heap.”
  4. Make sure you open the Heap panel on the right side of the screen.
  5. Tap the “Cause GC” button2.

This will put some numbers in that chart. The one we should focus on is “Allocated,” which shows you how much memory the Dalvik VM currently has given your app. This can stretch and shrink a bit, but there’s an upper limit (the size of which depends on the device). If you exceed the upper limit, you pop out an OOM and the app crashes.

This is a great tool to keep an eye on while you develop, since it shows a live snapshot of the system after any garbage collection cycle. If you ever notice the allocated memory gradually increasing without ever letting anything go, that’s a good indication that you might have a memory leak.3

EXAMINATION 2: MAT & HPROF — A.K.A., “THE HUNT”

There are some acronyms for you, huh?

“MAT,” the Eclipse Memory Analyzer tool, can read a file that your virtual machine generates (Remember that one we talked about in the last post? It’s called Dalvik). That file, called a “heap dump,” represents the set of all objects currently stored on your process’s heap4. That means you can actually poke around the metadata of the objects you’re using during runtime.

What you’ll need:

  • Eclipse (the Google provided “ADT” version works well here).
  • MAT.
  • If you’re not using the DDMS plugin, you’ll need to manually convert the Dalvik profile into an .hprof file.

Plot a course

Run the MemoryLeek project on an emulator5. You should see a white screen with a slowly blinking image. Rotate the emulator ten or so times (either 7 on the numpad or Cntrl+F12). Now, return to Eclipse, and open the DDMS perspective once again. This time, we’re aiming for the green disc icon with an arrow attached — indicating you want to generate a heap dump. Go ahead and click it, and you should see a statement in the Android log that looks like:

Java

1

I/dalvikvm(1948): hprof: dumping heap strings to "[DDMS]".

That’s good. Now leave it for a bit, because it could take a couple of minutes to generate (and the emulator is frozen until it finishes).

Once the output is ready, it should prompt you about some different types of reports. (If you instead see a prompt to save a file, go ahead and save it somewhere, then use the SDK tool hprof-conv to convert it to the appropriate format, and manually open it with Eclipse’s MAT). Once you have the “reports” prompt, just cancel out of it — we’re not going to use any pre-set reports for this.

Load your ammo

Hooray! If you’re reading this, you’re hopefully looking at some kind of graph of your app’s current memory state. In my case, a pie chart.

Now what?

Let’s try poking around a bit. Click the little bar chart icon in the top left, that says “Create a histogram…” when you hover over it. This will show you a list of all the objects currently allocated, in no particular order.

You’re looking at the name and package of the objects in the first column, the number of that kind of object in existence at the moment in the next column and then some representation of the total heap sizes in the third and fourth columns6.

It might be interesting to sort by size or count to see where the majority of memory is being used in your code7. If you right-click on one of these listings, you can get some cool options, like all instances of objects of that type with all the references that keep it from being garbage collected.

But wait, we’re supposed to be hunting for something, right? We need a target of some kind.

Tracking the game

There’s a lot of noise in an app’s memory space. Fortunately, we can narrow it down in a few ways.

First, try applying filtering to this list. In the first row, you can enter text. Since you almost always want to take a closer look at your code, I suggest entering something like  “com.example.memoryleek”. This should filter down to a handful of entries.

Gazing upon these, I’m hoping you notice something horrifying. If you don’t, I recommend taking another look at Part 1 of this series. Hopefully you will figure out what the worst thing in the world to leak would be.

Hint: it’s Activities.

And, good Lord, I have 24 instances of LeekActivity right now! That’s totally not OK.

Why might this be?

Well, kindly, MAT has a way to tell us. You can right-click that list item, and select “Merge Shortest Paths to GC Roots”, excluding WeakReferences (remember, WeakReferences will have no effect on what is retained). This means we want to see what memory root all these objects have in common. That should indicate if there’s something retaining all of them at once, ergo, a leak of some kind!

In this case, there are 3 roots. Two of them are external to this project, so aren’t likely culprits. But, that LeekManager instance looks suspicious….

A-Ha! If you open it up, you can see that there’s a LinkedList called “listeners” on LeekManager that has a reference to all of those Activities.

But, where did that come from?

Well, check this out:

// In LeekFragment.class:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Add this fragment as a leek listener so
    // it can update its view accordingly
    LeekManager.get().addListener(this);
}

Every time our LeekFragment is created, we add it as a LeekListener to the LeekManager singleton. But, when we did those rotations, the Fragment was never removed as a listener. The Fragment has a reference to the parent Activity, and the parent LeekActivity has references to all the other view elements.

Taking the shot

There’s our leak. Fixing it? Easy: LeekFragment needs to be removed from LeekManager upon its onDestroy() lifecycle method.

Now, the above code looks like:

// In LeekFragment.class:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Add this fragment as a leek listener so
    // it can update its view accordingly
    LeekManager.get().addListener(this);
}

@Override
public void onDestroy() {
    super.onDestroy();

    LeekManager.get().removeListener(this);
}

And when we run the app, we don’t see any more indications of leaky memory! Hoorah!

时间: 2024-10-18 19:34:57

HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID (PART 2 OF 2)的相关文章

Android Memory Management, OutOfMemoryError

A Android框架强制每个进程的24 MB内存限制.在一些旧的设备,如在G1,限制为16 MB 更低,更重要的是,由位图使用的内存限制.处理图像的应用程序,它是很容易达到此限制,并获得与OOM 异常死亡 的过程:E / dalvikvm堆(12517):1048576字节外部分配这个 过程中过大的E / GraphicsJNI(12517): VM将不会让我们分配1048576字节 / AndroidRuntime(12517):关闭VM / dalvikvm(12517):主题ID = 1

Objective-C Memory Management Being Exceptional 异常处理与内存

Objective-C Memory Management ? ?Being Exceptional ?异常处理与内存 3.1Cocoa requires that all exceptions must be of type NSException cocoa?需要所有的异常是NSException类型的. so even though you can throw an exception from other objects, Cocoa isn't set up to deal with

cURL的内存溢出 leaks memory

leaks memory http://stackoverflow.com/questions/26690026/php-curl-loop-leaking-memory up vote2down vote Stories from the internet indicate that curl_setopt($ch, CURLOPT_RETURNTRANSFER, true) is broken in for some PHP/cURL versions: #13225 Memmory lea

Fixed Partition Memory Management UVALive - 2238 建图很巧妙 km算法左右顶点个数不等模板以及需要注意的问题 求最小权匹配

/** 题目: Fixed Partition Memory Management UVALive - 2238 链接:https://vjudge.net/problem/UVALive-2238 题意:lv 思路:lrjP352. 来自lrj训练指南. n个程序作为左边结点, n*m个结点在右边:由于只要求n个程序在右边能找到的匹配点,km算法可以求解.修改nx,ny的值. if(f[i][j]==-1){ for(int k = 1; k <= n; k++) love[i][j*n+k-

Objective -C Memory Management 内存管理 第一部分

Objective -C Memory Management??内存管理??第一部分 Memory management is part of a more general problem in programming called resource management. 内存管理是资源管理的一部分. Every computer system has finite resources for your program to use. These include memory, open fi

2015.12.21 内存管理(memory management)

Memory Management 1.什么是内存管理? 程序在运行过程中管理内存分配的过程,当需要内存的时候就申请一片内存空间,不需要就释放掉. 2.如何去管理内存 站在分配对象拥有权的角度来操作内存. 3.内存管理的两种办法 a. MRR(Manual Retain Release)手动管理,实现的机制:reference counting(引用计数机制). b. ARC(Auto Reference Counting)自动引用计数,实现机制:系统在程序编译阶段自动添加了释放对象的办法. 4

《modern operating system》 chapter 3 MEMORY MANAGEMENT 笔记

MEMORY MANAGEMENT The part of the operating system that manages (part of) the memory hierarchy is called thememory manager 这章感觉有点多...80 多页..看完都看了两天多,做笔记就更有点不想...有点懒了..但是要坚持下去,可以自己较劲 对于内存的抽象,最简单的抽象就是...没有抽象 和第一次看不一样,把summary放在最前面,对整个mamory management的

Summary of Memory Management Methods

Summary of Memory Management Methods Table 18-1 summarizes the various memory management methods. If you do not enable automatic memory management, then you must separately configure one memory management method for the SGA and one for the PGA. Note:

Automatic Tuning of Memory Management

4.2.2 Automatic Tuning of Memory Management Two memory management initialization parameters, MEMORY_TARGET and MEMORY_MAX_TARGET, enable automatic management of the System Global Area (SGA), Program Global Area (PGA), and other memory required to run