如何使用ddms update heap置灰Heap查看Android应用内存情况

Android 中查看内存的使用情况集常用adb命令
在IDE中查看Log信息
当程序运行垃圾回收的时候,会打印一条Log信息,其& 26684;式如下:
D dalvikvm:
GC_Reason表示导致垃圾回收的原因以及当前的回收类型,包括以下几类:
1. 在IDE中查看Log信息
当程序运行垃圾回收的时候,会打印一条Log信息,其格式如下:
D/dalvikvm:
GC_Reason表示导致垃圾回收的原因以及当前的回收类型,包括以下几类:
GC_CONCURRENT:当堆中对象数量达到一定是触发的垃圾收集
GC_FOR_MALLOC:在内存已满的情况下分配内存,此时会暂停程序并回收内存
GC_HPROF_DUMP_HEAP:创建FPFOR文件来分析Heap时所造成的垃圾收集
GC_EXPLICIT: 程序调用了垃圾收集函数System.gc
GC_EXTERNAL_ALLOC: 出现在API 10及以下,为外部分配内存(native memory or NIO buffer)所造成的垃圾回收,高版本全部分配在Dalvik Heap中。
Amount_freed 表示此次回收的内存
Heap_stats 表示空闲内存百分比和存活对象大小/堆的总大小
External_memory_stats 表示API 10及以下的外部分配内存,已分配内存/导致垃圾回收的界限
Pause_time 暂停时间,一个表示开始回收垃圾的时间,另一个表示回收结束的暂停时间
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free K, external K, paused 2ms+2ms
注意这条信息中的 “ K” 值,这代表着程序使用的heap大小。
2.使用DDMS
Eclipse中的DDMS提供了一个观察内存使用情况的GUI,当我们不断点击Cause GC时,就会看到当前程序的Heap,使用比较方便,具体用法可以Google一下。
3.使用adb dumpsys 命令
adb是一个非常强大的工具,使用adb查看应用程序内存使用情况可按如下格式在命令行里查看内存使用情况:
adb shell dumpsys meminfo
其中,package_name 也可以换成程序的pid,pid可以通过 adb shell top | grep app_name 来查找,下图是某个程序的内存使用情况:
重点关注如下几个字段:
(1) Native/Dalvik 的 Heap 信息
具体在上面的第一行和第二行,它分别给出的是JNI层和Java层的内存分配情况,如果发现这个值一直增长,则代表程序可能出现了内存泄漏。
(2) Total 的 PSS 信息
这个值就是你的应用真正占据的内存大小,通过这个信息,你可以轻松判别手机中哪些程序占内存比较大了。vcD4KPHA+PGJyPgo8L3A+CjxwPjxzdHJvbmc+NC4gyrnTw2FkYiBzaGVsbCBwcm9jcmFuazwvc3Ryb25nPjxicj4Kyta7+tbQtcRzaMrHvq25/b6rvPK5/bXEo6zT0NCpyta7+r/JxNzDu9PQIHByb2NyYW5rIMP8we6jrL/J0tTKudPDZ2VueW1vdGlvbsSjxOLG96Osu/LKx9fUvLqwstewcHJvY3JhbmvD/MHuoaPKudPDcHJvY3JhbmvKsaOsw/zB7tDQtcTK5LP2yOvPws28o7o8L3A+CjxwPjxpbWcgc3JjPQ=="/uploadfile/Collfiles/1.jpg" alt="\">
可以看到,在linux下表示内存的耗用情况有四种不同的表现形式:
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
VSS:VSS表示一个进程可访问的全部内存地址空间的大小。这个大小包括了进程已经申请但尚未使用的内存空间。在实际中很少用这种方式来表示进程占用内存的情况,用它来表示单个进程的内存使用情况是不准确的。
RSS:表示一个进程在RAM中实际使用的空间地址大小,包括了全部共享库占用的内存,这种表示进程占用内存的情况也是不准确的。
PSS:表示一个进程在RAM中实际使用的空间地址大小,它按比例包含了共享库占用的内存。假如有3个进程使用同一个共享库,那么每个进程的PSS就包括了1/3大小的共享库内存。这种方式表示进程的内存使用情况较准确,但当只有一个进程使用共享库时,其情况和RSS一模一样。
USS:表示一个进程本身占用的内存空间大小,不包含其它任何成分,这是表示进程内存大小的最好方式!
可以看到:VSS>=RSS>=PSS>=USS
5.其它常用命令命令:
adb shell kill PIDNumber
死你想杀死的后台进程来模拟某种 bug 的复现条件。
adb shell ps
查看当前终端中的进程信息
那么如何在代码中判断当前的硬件系统有多少的 RAM 呢?在 Framework
ProcessList.java 中有如下代码可用:
ProcessList() {
MemInfoReader minfo = new MemInfoReader();
minfo.readMemInfo();
mTotalMemMb = minfo.getTotalSize()/();
查看进程占用cpu的情况:adb shell top -n 1 -d 0.5 " grep proc_ idAndroid内存分析MAT(eclipse memory analyzer)使用_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
Android内存分析MAT(eclipse memory analyzer)使用
上传于||文档简介
&&内​存​分​析​利​器​。​解​决​O​O​M​问​题
阅读已结束,如果下载本文需要使用2下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩5页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢Android开发实践:检测App的内存占用和泄漏_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Android开发实践:检测App的内存占用和泄漏
来源:Linux社区&
作者:ticktick
前段时间开发的应用,每次都是在运行了半个小时左右后突然挂掉了,很是莫名其妙,也不知道哪里出了问题,后来一步步排查,发现问题出在JNI层,一个被频繁调用的函数分配的内存忘记释放,导致内存泄漏。
这次问题使我明白,别以为Android程序是基于Java语言,有强大的垃圾回收机制,就完全不用担心内存问题,其实Android程序也要特别小心你的内存,因为毕竟手机不比PC机,内存是极其有限的,在内存不够的时候,系统随时会Kill掉你的程序。目前我所了解到的,容易发生内存问题的地方如下:
(1) 操作Bitmap对象,一定要注意,在不使用的时候 recycle
(2) 访问数据库,一定要记得关闭游标
(3) 涉及JNI层的代码,由于JNI层是采用C/C++编写,需要自己管理内存的分配/回收,所以要慎重小心。
那么,Android开发中,有什么有效的方法可以检测内存使用情况以及内存泄漏呢?
这里主要介绍三种方法:
1. 程序的Log信息
程序在进行垃圾回收的时候,会打印一条Log信息(logcat窗口),例如:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free K, external K, paused 2ms+2ms
注意这条信息中的 & K& 值,这代表着程序使用的heap大小,如果这个值一直在增加,而从来不减小,那么就代表着你的程序存在着内存泄漏。
2. DDMS的Heap信息
Eclipse开发环境还提供了一种更加直观的方法来查看App的Heap信息,操作方式如下:
(1)& 连接手机,运行程序,假设是 com.ticktick.test 程序
(2)& 点击DDMS按钮,在左侧的Device窗口选中你要检测的程序(com.ticktick.test )
(3)& 点击Device窗口工具栏的第二个图标(Update Heap),
(4)& 点击右边的窗口的Cause GC按钮,即可得到当前程序的Heap信息
同样,随着程序的运行,多次点击得到的Heap大小,如果只增不减的话,也昭示着你的程序有内存泄漏。
3.& adb命令查看内存信息
其实,最全面最简单的方式还是用adb命令来查看程序的内存占用和内存泄漏情况,打开命令行窗口,adb命令的格式如下:
adb shell dumpsys meminfo &package_name&
其中,package_name 也可以换成程序的pid,pid可以通过 adb shell top | grep app_name 来查找,在命令行窗口运行上述命令,得到的我的 com.ticktick.test 程序的内存情况如下所示:
这里得到的信息非常多,重点关注如下几个字段:
(1) Native/Dalvik 的 Heap 信息
具体在上面的第一行和第二行,它分别给出的是JNI层和Java层的内存分配情况,如果发现这个值一直增长,则代表程序可能出现了内存泄漏。
(2) Total 的 PSS 信息
这个值就是你的应用真正占据的内存大小,通过这个信息,你可以轻松判别手机中哪些程序占内存比较大了。
关于Android开发中内存的使用情况和内存泄漏的检测就简单介绍到这里,基本上用以上三种方式都能够定位内存泄漏问题,平时在使用Bitmap,数据库和JNI层C/C++编程的时候,注意一点就行。另外,如果想深入了解文中的一些详细内容,可以参考Google官方提供的两篇文章,它们有着更详细的论述《Investigating Your RAM Usage》,《Managing Your App Memory》,有任何疑问或者不清楚的地方,欢迎留言或者来信lujun.交流。
更多Android相关信息见 专题页面
相关资讯 & & &
& (12/16/:11)
& (12/04/:03)
& (12/04/:48)
& (12/04/:35)
& (12/04/:52)
& (12/04/:36)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款1134人阅读
Android是为移动设备而设计的,所以应该关注应用的内存使用情况。尽管Android的Dalvik虚拟机会定期执行垃圾回收操作,但这也不意味着就可以忽视应用在何时何处进行内存分配和释放。为了提供良好的用户体验,做到系统在不同应用间流畅切换,当用户和应用无交互时,避免应用不必要的内存消耗是很重要的。
尽管在开发过程中很好的遵守了(&)中的原则(也是应该遵守的),仍然可能会有对象泄露或引入其他的内存bug。对此的安全性,可以采取的措施就是等一系列安全的加密技术。想详细了解的可以关注下,专业的移动应用安全智能服务提供商!唯一来确定应用使用了尽可能少的内存的方法,就是使用工具来分析应用的内存使用情况。
解析日志信息
最简单的调查应用内存使用情况的地方就是Dalvik日志信息。可以在(输出信息可以在Device&Monitor或者IDE中查看到,例如Eclipse和Android&Studio)中找到这些日志信息。每次有垃圾回收发生,logcat会打印出带有下面信息的日志消息:
D/dalvikvm: &GC_Reason& &Amount_freed&, &Heap_stats&, &External_memory_stats&, &Pause_time&
触发垃圾回收执行的原因和垃圾回收的类型。原因主要包括:
GC_CONCURRENT
并发垃圾回收,当堆开始填满时触发来释放内存。
GC_FOR_MALLOC
堆已经满了时应用再去尝试分配内存触发的垃圾回收,这时系统必须暂停应用运行来回收内存。
GC_HPROF_DUMP_HEAP
创建HPROF文件来分析应用时触发的垃圾回收。
GC_EXPLICIT
显式垃圾回收,例如当调用&(应该避免手动调用而是要让垃圾回收器在需要时主动调用)时会触发。
GC_EXTERNAL_ALLOC
这种只会在API&10和更低的版本(新版本内存都只在Dalvik堆中分配)中会有。回收外部分配的内存(例如存储在本地内存或NIO字节缓冲区的像素数据)。
执行垃圾回收后内存释放的数量。
空闲的百分比和(活动对象的数量)/(总的堆大小)。
外部内存状态
API&10和更低版本中的外部分配的内存(分配的内存大小)/(回收发生时的限制值)。
越大的堆的暂停时间就越长。并发回收暂停时间分为两部分:一部分在回收开始时,另一部分在回收将近结束时。
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free K, external K, paused 2ms+2ms
随着这些日志消息的增多,注意堆状态(上面例子中的K)的变化。如果值一直增大并且不会减小下来,那么就可能有内存泄露了。
查看堆的更新
为了得到应用内存的使用类型和时间,可以在Device&Monitor中实时查看应用堆的更新:
1.打开Device&Monitor。
从&sdk&/tools/路径下加载monitor工具。
2.在Debug&Monitor窗口,从左边的进程列表中选择要查看的应用进程。
3.点击进程列表上面的Update&Heap。
4.在右侧面板中选择Heap标签页。
Heap视图显示了堆内存使用的基本状况,每次垃圾回收后会更新。要看更新后的状态,点击Gause&GC按钮。
图1.Device&Monitor工具显示[1]&Update&Heap和&[2]&Cause&GC按钮。右边的Heap标签页显示堆的情况。
跟踪内存分配
当要减少内存问题时,应该使用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来更新分配列表。
列表显示了所有的当前分配和512大小限制的环形缓冲区的情况。点击行可以查看分配的堆栈跟踪信息。堆栈不只显示了分配的对象类型,还显示了属于哪个线程哪个类哪个文件和哪一行。
图2.&Device&Monitor工具显示了在Allocation&Tracker中当前应用的内存分配和堆栈跟踪的情况。
注意:总会有一些分配是来自与&DdmVmInternal&和&allocation&tracker本身。
尽管移除掉所有严重影响性能的代码是不必要的(也是不可能的),但是allocation&tracker还是可以帮助定位代码中的严重问题。例如,应用可能在每个draw操作上创建新的对象。把对象改成全局变量就是一个很简单的改善性能的修改。
查看总体内存分配
为了进一步的分析,查看应用内存中不同内存类型的分配情况,可以使用下面的&&&命令:
adb shell dumpsys meminfo &package_name&
应用当前的内存分配输出列表,单位是千字节。
当查看这些信息时,应当熟悉下面的分配类型:
私有(Clean&and&Dirty) 内存
进程独占的内存。也就是应用进程销毁时系统可以直接回收的内存容量。通常来说,“private&dirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储,因此不能做分页存储到外存(Android不支持swap)。所有分配的Dalvik堆和本地堆都是“private&dirty”内存;Dalvik堆和本地堆中和Zygote进程共享的部分是共享dirty内存。
&实际使用内存 (PSS)
这是另一种应用内存使用的计算方式,把跨进程的共享页也计算在内。任何独占的内存页直接计算它的PSS值,而和其它进程共享的页则按照共享的比例计算PSS值。例如,在两个进程间共享的页,计算进每个进程PPS的值是它的一半大小。
PSS计算方式的一个好处是:把所有进程的PSS值加起来就可以确定所有进程总共占用的内存。这意味着用PSS来计算进程的实际内存使用、进程间对比内存使用和总共剩余内存大小是很好的方式。
例如,下面是平板设备中Gmail进程的输出信息。它显示了很多信息,但是具体要讲解的是下面列出的一些关键信息。
注意:实际看到的信息可能和这里的稍有不同,输出的详细信息可能会根据平台版本的不同而不同。
** MEMINFO in pid 9953 [com.google.android.gm] **
Shared Private
Shared Private
Native Heap
Dalvik Heap
Dalvik Other
Other mmap
ViewRootImpl:
AppContexts:
Activities:
AssetManagers:
Local Binders:
Proxy Binders:
Death Recipients:
OpenSSL Sockets:
MEMORY_USED:
PAGECACHE_OVERFLOW:
MALLOC_SIZE:
通常来说,只需关心Pss&Total列和Private&Dirty列就可以了。在一些情况下,Private&Clean列和Heap&Alloc列也会提供很有用的信息。下面是一些应该查看的内存分配类型(行中列出的类型):
Dalvik&Heap
应用中Dalvik分配使用的内存。Pss&Total包含所有的Zygote分配(如上面PSS定义所描述的,共享跨进程的加权)。Private&Dirty是应用堆独占的内存大小,包含了独自分配的部分和应用进程从Zygote复制分裂时被修改的Zygote分配的内存页。
&注意:新平台版本有Dalvik&Other这一项。Dalvik&Heap中的Pss&Total和Private&Dirty不包括Dalvik的开销,例如即时编译(JIT)和垃圾回收(GC),然而老版本都包含在Dalvik的开销里面。
&Heap&Alloc是应用中Dalvik堆和本地堆已经分配使用的大小。它的值比Pss&Total和Private&Dirty大,因为进程是从Zygote中复制分裂出来的,包含了进程共享的分配部分。
&.so&mmap和.dex&mmap
mmap映射的.so(本地)&和.dex(Dalvik)代码使用的内存。Pss&Total&包含了跨应用共享的平台代码;Private&Clean是应用独享的代码。通常来说,实际映射的内存大小要大一点——这里显示的内存大小是执行了当前操作后应用使用的内存大小。然而,.so&mmap&的private&dirty比较大,这是由于在加载到最终地址时已经为本地代码分配好了内存空间。
无法归类到其它项的内存页。目前,这主要包含大部分的本地分配,就是那些在工具收集数据时由于地址空间布局随机化(Address&Space&Layout&Randomization&,ASLR)不能被计算在内的部分。和Dalvik堆一样,&Unknown中的Pss&Total把和Zygote共享的部分计算在内,Unknown中的Private&Dirty只计算应用独自使用的内存。
进程总使用的实际使用内存(PSS),是上面所有PSS项的总和。它表明了进程总的内存使用量,可以直接用来和其它进程或总的可以内存进行比较。
Private&Dirty和Private&Clean是进程独自占用的总内存,不会和其它进程共享。当进程销毁时,它们(特别是Private&Dirty)占用的内存会重新释放回系统。Dirty内存是已经被修改的内存页,因此必须常驻内存(因为没有swap);Clean内存是已经映射持久文件使用的内存页(例如正在被执行的代码),因此一段时间不使用的话就可以置换出去。
ViewRootImpl
进程中活动的根视图的数量。每个根视图与一个窗口关联,因此可以帮助确定涉及对话框和窗口的内存泄露。
AppContexts和Activities
当前驻留在进程中的和对象的数量。可以很快的确认常见的由于静态引用而不能被垃圾回收的泄露的&对象。这些对象通常有很多其它相关联的分配,因此这是追查大的内存泄露的很好办法。
注意:&和&&对象也持有所在的引用,因此,持有&或&&对象也可能会导致应用泄露。
获取堆转储
堆转储是应用堆中所有对象的快照,以二进制文件HPROF的形式存储。应用堆转储提供了应用堆的整体状态,因此在查看堆更新的同时,可以跟踪可能已经确认的问题。
检索堆转储:
1.打开Device&Monitor。
从&sdk&/tools/路径下加载monitor工具。
2.在DDMS窗口,从左侧面板选择应用进程。
3.点击Dump&HPROF&file,显示见图3。
4.在弹出的窗口中,命名HPROF文件,选择存放位置,然后点击Save。
图3.Device&Monitor工具显示了[1]&Dump&HPROF&file按钮。
如果需要能更精确定位问题的堆转储,可以在应用代码中调用来生成堆转储。
堆转储的格式基本相同,但与Java&HPROF文件不完全相同。Android堆转储的主要不同是由于很多的内存分配是在Zygote进程中。但是由于Zygote的内存分配是所有应用进程共享的,这些对分析应用堆没什么关系。
为了分析堆转储,你需要像jhat或(MAT)一样的标准工具。当然,第一步需要做的是把HPROF文件从Android的文件格式转换成J2SE&HRPOF的文件格式。可以使用&sdk&/platform-tools/路径下的hprof-conv工具来转换。hprof-conv的使用很简单,只要带上两个参数就可以:原始的HPROF文件和转换后的HPROF文件的存放位置。例如:
hprof-conv heap-original.hprof heap-converted.hprof
注意:如果使用的是集成在Eclipse中的DDMS,那么就不需要再执行HPROF转换操作——默认已经转换过了。
现在就可以在MAT中加载转换过的HPROF文件了,或者是在可以解析J2SE&HPROF格式的其它堆分析工具中加载。
分析应用堆时,应该查找由下导致的内存泄露:
使用Eclipse内存分析工具
(MAT)是一个可以分析堆转储的工具。它是一个功能相当强大的工具,功能远远超过这篇文档的介绍,这里只是一些入门的介绍。
在MAT中打开类型转换过的HPROF文件,在总览界面会看到一张饼状图,它展示了占用堆的最大对象。在图表下面是几个功能的链接:
正常来说类的实例的数量应该是确定的,可以用这个视图找到额外的类的实例。例如,一个常见的源码泄露就是类有额外的实例,而正确的是在同一时间应该只有一个实例。要找到特定类的实例,在列表顶部的&Regex&域中输入类名查找。
当一个类有太多的实例时,右击选择List&objects&with&incoming&references。在显示的列表中,通过右击选择Path&To&GC&Roots&&exclude&weak&references来确定保留的实例。
应该注意的是那些保留的部分堆大小粗略等于通过、或观察到的泄露大小的对象。
当看到可疑项时,右击选择Path&To&GC&Roots&exclude&weak&references。打开新的标签页,标签页中列出了可疑泄露的对象的引用。
注意:在靠近饼状图中大块堆的顶部,大部分应用会显示的实例,但这通常只是因为在应用使用了很多res/路径下的资源。
图4.MAT显示了Histogram view和搜索”MainActivity”的结果。
想要获得更多关于MAT的信息,请观看2011年Google&I/O大会的演讲–《》(),在大约&的时候有关于MAT的实战演讲。也可以参考文档《》()。
对比堆转储
为了查看内存分配的变化,比较不同时间点应用的堆状态是很有用的方法。对比两个堆转储可以使用MAT:
1.按照上面描述得到两个HPROF文件,具体查看章节。
2.在MAT中打开第一个HPROF文件(File&Open&Heap&Dump)。
3.在Navigation&History视图(如果不可见,选择Window&Navigation&History),右击Histogram,选择Add&to&Comp&are&Basket。
4.打开第二个HRPOF文件,重复步骤2和3。
5.切换到Compare&Basket视图,点击Compare&the&Results(在视图右上角的红色“!”图标)。
触发内存泄露
使用上述描述工具的同时,还应该对应用代码做压力测试来尝试复现内存泄露。一个检查应用潜在内存泄露的方法,就是在检查堆之前先运行一会。泄露会慢慢达到分配堆的大小的上限值。当然,泄露越小,就要运行应用越长的时间来复现。
也可以使用下面的方法来触发内存泄露:
1.在不同Activity状态时,重复做横竖屏切换操作。旋转屏幕可能导致应用泄露&、&或&对象,因为系统会重新创建&,如果应用在其它地方持有这些对象的引用,那么系统就不能回收它们。
2.在不同Activity状态时,做切换应用操作(切换到主屏幕,然后回到应用中)。
提示:也可以使用monkey测试来执行上述步骤。想要获得更多运行 monkey 测试的信息,请查阅&&文档。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:83943次
积分:1977
积分:1977
排名:第15108名
原创:84篇
评论:84条
(8)(12)(13)(8)(16)(3)(9)(13)(14)

我要回帖

更多关于 ddms heap 的文章

 

随机推荐