注意:本篇文章是本人阅读相关文章所写下的总结,方便以后查阅,所有内容非原创,侵权删。
本篇文章内容来自于:
如何检查 Android 应用的内存使用情况
目录
- 解析日志信息logcat
- 使用DDMS查看堆的更新Heap
- 使用DDMS跟踪内存分配Allocation Tracker
- 查看总体内存分配 adb
1. 解析日志信息logcat
//GC_CONCURRENT GC原因
//freed 2049K 释放数量 执行垃圾回收后内存释放的数量
//65% free 3571K/9991K 堆状态 空闲的百分比和(活动对象的数量)/(总的堆大小)。
//external 4703K/5261K 外部内存状态
//API 10和更低版本中的外部分配的内存(分配的内存大小)/(回收发生时的限制值)。
//paused 2ms+2ms 暂停时间
//越大的堆的暂停时间就越长。并发回收暂停时间分为两部分:一部分在回收开始时,另一部分在回收将近结束时。
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
GC原因 触发垃圾回收执行的原因和垃圾回收的类型。
- GC_CONCURRENT
并发垃圾回收,当堆开始填满时触发来释放内存。 - GC_FOR_MALLOC
堆已经满了时应用再去尝试分配内存触发的垃圾回收,这时系统必须暂停应用运行来回收内存。 - GC_HPROF_DUMP_HEAP
创建HPROF文件来分析应用时触发的垃圾回收。 - GC_EXPLICIT
显式垃圾回收,例如当调用gc()(应该避免手动调用而是要让垃圾回收器在需要时主动调用)时会触发。 - GC_EXTERNAL_ALLOC
这种只会在API 10和更低的版本(新版本内存都只在Dalvik堆中分配)中会有。回收外部分配的内存(例如存储在本地内存或NIO字节缓冲区的像素数据)。
随着这些日志消息的增多,注意堆状态(上面例子中的3571K/9991K)的变化。如果值一直增大并且不会减小下来,那么就可能有内存泄露了。
2. 使用DDMS查看堆的更新
具体操作看android IDE——通过DDMS查看app运行时所占内存情况
如何知道程序内存泄漏?
Heap视图中有一行数据是叫data object,即数据对象。它是我们app中大量存在的类类型的对象。
在data object中有一列 Total Size ,它的值就是当前进程中所有java对象的内存总量。
一般情况下,这个值决定是否内存泄漏。
如何判断?
1,不断的操作你的app,同时观察Total Size的值。
2,Total Size的值一般会稳定在一个正常范围内。
3,当我们在不断操作app的时候,内存会有一个先增加(不断的生成对象),后下降(对象被回收)。如果程序的代码处理良好,那么内存占用量会有一个明显的回落,并且稳定在一个正常水平。
4,如果你的代码没有很好的释放内存。那么,内存占用量就没有一个明显的回落,并且会越来越高,最终达到上限程序被kill掉。
3. 使用DDMS跟踪内存分配Allocation Tracker
当要减少内存问题时,应该使用Allocation Tracker来更好的了解内存消耗大户在哪分配。Allocation Tracker不仅在查看内存的具体使用上很有用,也可以分析应用中的关键代码路径,例如滑动。
例如,在应用中滑动列表时跟踪内存分配,可以看到内存分配的动作,包括在哪些线程上分配和哪里进行的分配。这对优化代码路径来减轻工作量和改善UI流畅性都极其有用。
使用Allocation Tracker:
1.打开Device Monitor 。
从<sdk>/tools/路径下加载monitor工具。
2.在DDMS窗口,从左侧面板选择应用进程。
3.在右侧面板中选择Allocation Tracker标签页。
4.点击Start Tracking。
5.执行应用到需要分析的代码路径处。
6.点击Get Allocations来更新分配列表。
4. 查看总体内存分配 adb
adb命令行:
adb shell dumpsys meminfo <package_name>
输出结果:
应用当前的内存分配输出列表,单位是千字节。
appledeMBP:~ apple$ adb shell dumpsys meminfo com.example.apple.encryptiondemo
Applications Memory Usage (in Kilobytes):
Uptime: 1305554068 Realtime: 5441384153
** MEMINFO in pid 22196 [com.example.apple.encryptiondemo] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 11162 11076 0 0 20480 12670 7809
Dalvik Heap 14090 13872 0 0 33928 25736 8192
Dalvik Other 1196 1192 0 0
Stack 356 356 0 0
Ashmem 2 0 0 0
Gfx dev 13210 11740 0 0
Other dev 4 0 4 0
.so mmap 4927 148 3796 0
.jar mmap 0 0 0 0
.apk mmap 2713 2672 0 0
.ttf mmap 19 0 0 0
.dex mmap 144 12 72 0
.oat mmap 1910 0 0 0
.art mmap 1655 1200 28 0
Other mmap 10 4 0 0
EGL mtrack 2764 2764 0 0
GL mtrack 3644 3644 0 0
Unknown 359 356 0 0
TOTAL 58165 49036 3900 0 54408 38406 16001
App Summary
Pss(KB)
------
Java Heap: 15100
Native Heap: 11076
Code: 6700
Stack: 356
Graphics: 18148
Private Other: 1556
System: 5229
TOTAL: 58165 TOTAL SWAP PSS: 0
Objects
Views: 20 ViewRootImpl: 1
AppContexts: 4 Activities: 1
Assets: 16 AssetManagers: 2
Local Binders: 13 Proxy Binders: 20
Parcel memory: 3 Parcel count: 15
Death Recipients: 2 OpenSSL Sockets: 0
WebViews: 0
SQL
MEMORY_USED: 0
PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0
私有(Clean and Dirty) 内存
进程独占的内存。也就是应用进程销毁时系统可以直接回收的内存容量。
通常来说,“private dirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储。
实际使用内存 (PSS)
另一种应用内存使用的计算方式,把跨进程的共享页也计算在内。
把所有进程的PSS值加起来就可以确定所有进程总共占用的内存