转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/23599453
我们在开发移动设备上得App的时候,必须考虑RAM的使用情况,虽然Android有垃圾回收机制,但是这并不意味着你不需要关心内存分配和释放的问题。为了提供优秀的用户体验,你的程序不必消耗没有必要的内存。
虽然你已经有了一些管理APP内存的经验,但是在开发过程中你还是会或多或少的遇到一些内存泄露和其他的内存问题,这就需要我们能分析我们的app内存使用情况,下面我们讲解怎么进行分析。
Log信息
分析你的app内存使用情况最简单的地方就是查看Dalvik的log信息。你可以在logcat中查看到这些信息。
每次GC回收发生的时候,logcat都会打印下面这些信息:
D/dalvikvm:<GC_Reason> <Amount_freed>, <Heap_stats>,<External_memory_stats>, <Pause_time>
1. GC Reason GC发生的原因和GC回收的类型。原因有以下几种:
GC_CONCURRENT | Heap即将填满导致并发的GC回收 |
GC_FOR_MALLOC | 当heap已经被占满了,这个时候你还尝试分配内存,促使GC发生,这时,系统会强制停掉你的程序。 |
GC_HPROF_DUMP_HEAP | 当你创建一个HPROF文件去分析heap的时候触发GC。 |
GC_EXPLICIT | 显示的调用GC回收,比如你调用了gc()(你应该避免这样做,应该使用系统自己的gc机制) |
GC_EXTERNAL_ALLOC | 这个只会发生在API10和以下的版本(新版本都只会在Dalvik heap上分配)。其他内存触发的GC,比如存在NIO byte buffers中得像素数据。 |
2. Amount freed:回收的内存大小。
3. Heap stats:空闲的内存百分比以及(现有对象大小)/(heap大小)
4. External memory stats:(API10及以下的其他内存分配大小)/(GC将发生的大小)。
5. Pause time:暂停时间,越大的heap暂停时间越久,并发的会显示两个pause:一个是回收开始,老外一个是回收快结束的时候。
例子:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65%free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
当有很多个这个类似的语句的时候,查看heap stats(比如上例中得3571k/9991k)是否持续增长,如果是,你可能就存在内存泄露的问题。
查看Heap情况
想要简单的了解你的程序的内存使用情况,可以实时的在DDMS中监控heap的使用情况:
1. 打开DDMS
2. 选中你的进程
3. 点击update heap
4. 在右边面板中选择heap标签栏
heap视图展示了heap使用的基本情况,会在每个GC后自动更新,查看变化情况,点击Cause GC按钮。
持续使用你的app,并且查看gc后heap的分配情况,可以帮助你找到某个分配过多内存的操作,可以帮助你分析哪里可以减少内存分配和释放资源。
跟踪分配情况
为了缩小内存问题的范围,你需要用到Allocation Tracker来更好的分析有问题的内存分配。
1. 打开DDMS
2. 选中你的进程
3. 在右边的面板中选中Allocation Tracker 标签页
4. 点击start tracking。
5. 持续和你的程序交付
6. 点击Get Allocations来更新分配情况。
这个表里面显示了最近的分配情况。点击其中的一行可以查看stack trace。它向你展示了分配的对象类型,在哪个线程中被分配,在哪个类以及哪个文件的哪一行。
例如,一些app常常会在每个draw中创建一个Paint,我们可以将这个object编程global成员来解决这个问题。
Capturing a Heap Dump
Heap dump就是heap中对象的一个快照,以二进制的形式保存,叫做HPROF。这个文件提供了你的app heap的全部使用情况,所以当你在刚才的步骤中发现问题时,你可以使用heap dump来查找问题原因。
打开DDMS
选中你的app进程
点击Dump HPROF file,如下图所示
在弹出的窗口中填入文件名和保存位置,点击save。
如果你想要更精确的在某个地方创建一个heap dump,你可以在你的代码中调用dumpHprofData函数。
但是android的HPROF文件和java的HPROF文件略有不同,主要是因为android有多的分配是在Zygote进程进行的。我们需要将android HPROF文件转换成J2SE HPROF文件格式。实际上现在的eclipse都已经帮我们集成了这样的转换工作。如果你的没有自动转换,你可以使用<sdk>/tools/文件夹下面的hprof-conv工具来转换这个文件,例如:
hprof-conv heap-original.hprof heap-converted.hprof
我们现在可以使用MAT(Eclipse Memory Analyzer Tool)来分析这个文件了。
在分析的时候,我们需要关注这些问题:
1. 长时间存在的对Activity,Context,View,Drawable和其他对象的引用。
2. 非静态的内部类(比如runnable,这个会持有Activitu的实例)
3. 没有必要的一直持有某个对象
参考
https://developer.android.com/tools/debugging/debugging-memory.html