如何看androidmemory monitorr的memory指标

如何检查 Android 应用的内存使用情况 - 安卓 - 伯乐在线
& 如何检查 Android 应用的内存使用情况
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&
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
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, 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&
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:
123456789101112131415161718192021222324252627282930
** MEMINFO in pid 9953 [com.google.android.gm] **&&&&&&&&&&&&&&&& Pss&&&& Pss&&Shared Private&&Shared Private&&&&Heap&&&&Heap&&&&Heap&&&&&&&&&&&&&& Total&& Clean&& Dirty&& Dirty&& Clean&& Clean&&&&Size&& Alloc&&&&Free&&&&&&&&&&&&&&------&&------&&------&&------&&------&&------&&------&&------&&------&&Native Heap&&&&&&0&&&&&& 0&&&&&& 0&&&&&& 0&&&&&& 0&&&&&& 0&&&&7800&&&&7637(6)&&126&&Dalvik Heap&& 5110(3)&&&&0&&&&4136&&&&4988(3)&&&&0&&&&&& 0&&&&9168&&&&8958(6)&&210 Dalvik Other&& 2850&&&&&& 0&&&&2684&&&&2772&&&&&& 0&&&&&& 0&&&&&&&&Stack&&&& 36&&&&&& 0&&&&&& 8&&&&&&36&&&&&& 0&&&&&& 0&&&&&& Cursor&&&&136&&&&&& 0&&&&&& 0&&&& 136&&&&&& 0&&&&&& 0&&&&&& Ashmem&&&& 12&&&&&& 0&&&&&&28&&&&&& 0&&&&&& 0&&&&&& 0&&&&Other dev&&&&380&&&&&& 0&&&&&&24&&&& 376&&&&&& 0&&&&&& 4&&&& .so mmap&& 5443(5) 1996&&&&2584&&&&2664(5) 5788&&&&1996(5)&&&&.apk mmap&&&&235&&&&&&32&&&&&& 0&&&&&& 0&&&&1252&&&&&&32&&&&.ttf mmap&&&& 36&&&&&&12&&&&&& 0&&&&&& 0&&&&&&88&&&&&&12&&&&.dex mmap&& 3019(5) 2148&&&&&& 0&&&&&& 0&&&&8936&&&&2148(5)&& Other mmap&&&&107&&&&&& 0&&&&&& 8&&&&&& 8&&&& 324&&&&&&68&&&&&&Unknown&& 6994(4)&&&&0&&&& 252&&&&6992(4)&&&&0&&&&&& 0&&&&&&&&TOTAL&&24358(1) 4188&&&&9724&& 17972(2)16388&&&&4260(2)16968&& 16595&&&& 336& Objects&&&&&&&&&&&&&& Views:&&&&426&&&&&&&& ViewRootImpl:&&&&&&&&3(8)&&&&&&&& AppContexts:&&&&&&6(7)&&&&&&&&Activities:&&&&&&&&2(7)&&&&&&&&&&&&&&Assets:&&&&&&2&&&&&&&&AssetManagers:&&&&&&&&2&&&&&& Local Binders:&&&& 64&&&&&&&&Proxy Binders:&&&&&& 34&&&&Death Recipients:&&&&&&0&&&& OpenSSL Sockets:&&&&&&1& SQL&&&&&&&& MEMORY_USED:&& 1739&&PAGECACHE_OVERFLOW:&& 1164&&&&&&&&&&MALLOC_SIZE:&&&&&& 62
通常来说,只需关心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
hprof-conv heap-original.hprof heap-converted.hprof
注意:如果使用的是集成在Eclipse中的DDMS,那么就不需要再执行HPROF转换操作——默认已经转换过了。
现在就可以在MAT中加载转换过的HPROF文件了,或者是在可以解析J2SE HPROF格式的其它堆分析工具中加载。
分析应用堆时,应该查找由下导致的内存泄露:
对Activity、Context、View、Drawable的长期引用,以及其它可能持有Activity或Context容器引用的对象
非静态内部类(例如持有Activity实例的Runnable)
不必要的长期持有对象的缓存
使用Eclipse内存分析工具
(MAT)是一个可以分析堆转储的工具。它是一个功能相当强大的工具,功能远远超过这篇文档的介绍,这里只是一些入门的介绍。
在MAT中打开类型转换过的HPROF文件,在总览界面会看到一张饼状图,它展示了占用堆的最大对象。在图表下面是几个功能的链接:
Histogram view显示所有类的列表和每个类有多少实例。
正常来说类的实例的数量应该是确定的,可以用这个视图找到额外的类的实例。例如,一个常见的源码泄露就是类有额外的实例,而正确的是在同一时间应该只有一个实例。要找到特定类的实例,在列表顶部的&Regex&域中输入类名查找。
当一个类有太多的实例时,右击选择List objects&with incoming references。在显示的列表中,通过右击选择Path To GC Roots& exclude weak references来确定保留的实例。
Dominator tree是按照保留堆大小来显示的对象列表。
应该注意的是那些保留的部分堆大小粗略等于通过、或观察到的泄露大小的对象。
当看到可疑项时,右击选择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 测试的信息,请查阅
关于作者:
可能感兴趣的话题
关于安卓频道
安卓频道分享Android开发文章,精选工具和安卓相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2017 伯乐在线Memory Monitor 是android studio 提供的性能分析工具, 可以通过视图直观的看到android应用的内存,CPU占用情况。
Memory Monitor可以反映出当前操作带来的CPU和内存变化。
本文已收录于以下专栏:
相关文章推荐
全网最全的Android面试题总结,2017年跳槽的你必备
参考文章:
Memory Monitor Walkthrough
Memory Monitor能做什么?
实时查看App的内存分配情况
快速判断App是否由于GC操作造成卡顿
快速判断App的C...
手动打包怎么手动打包项目写完了,现在需要把应用上传到市场,问题出现—怎么把代码变成.apk(Android的可安装文件)。
1. 创建签名文件
2. 填写好签名参数
上图为 DDMS中的标签Heap,讲解如下:
打开DDMS界面,在左侧面板中选择你要观察的应用程序进程,然后点击Update Heap按钮,接着在右侧面板中点击Heap标签,之后不停地点击Cause ...
这个演示展示了在Android Studio中Memory Monitor工具基本的用法和流程。Memory Monitors实时报告了你的app分配的内存。
它的优势:
在图表中显示可用和已使用...
面试题:8个试剂,其中一个有毒,最少多少只小白鼠能检测出有毒试剂方法1:用3只小鼠,能组合成8种状态。
第一只喂食【1、3、5、7】四只试剂
第二只喂食【2、3、6、7】四只试剂
第三只喂食【4、5、...
AndroidStudio 中Memory控件台(显示器)提供了一个内存监视器。
我们可以通过它方便地查看应用程序的性能和内存使用情况,从而也就可以找到需要释放对象,查找内存泄漏等。主要功能有:显示...
安卓CPU Monitor:让你可以很容易地监视应用程序的CPU的实时使用情况。并显示在用户和内核模式中使用的总的处理器时间(包括所有内核)的百分比。
使用前提要求:测试时,程序要与真机或模拟器保持联...
Speed up your app
Android Studio版的特点Allocation Tracker(AS)工具比Allocation Tracker(Eclipse)工具强大的地方是更炫酷...
参考文章: Traceview Walkthrough
Android 编程下的 TraceView 简介及其案例实战
正确使用Android性能分析工具——TraceView
他的最新文章
讲师:王哲涵
讲师:韦玮
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)MemoryMonitor项目地址:简介:一个给开发者使用的 Android App 内存清理、监控工具。更多:&&&&&&&&&标签:一个给开发者使用的 Android App 内存清理、监控工具。
主要包括三部分内容:
通过内存清理可以模拟系统内存不足时对进程的回收。
通过内存监控可以监控指定应用程序使用的 total Pss 以及当前手机的内存使用情况,从而检测该应用是否存在内存泄漏。
整理了一些关于内存优化的 tips,以及一些可能导致内存溢出的场景示例,包含错误的写法和正确的写法。
1.内存清理
类似各种手机管家的 加速球,获取系统已用内存比率、可用内存大小,一键清理。
可以用于测试自己开发的 Activity、Fragment 健壮性,模拟 Activity、Fragment 被回收的场景,测试自己的程序是否完好的保存、恢复当前场景。
比如:打开你开发的某个 Activity、Fragment,切到后台,清理一次内存,在将其切回前台后,看会不会出现空指针异常,以及程序状态是否被恢复。
2.Pss 监控
Android 系统中的内存和 Linux 系统一样,存在着大量的共享内存。每个 APP 占内存会有私有和公共的两部分,我们可以通过 App 的 Pss 值,可以获取到这两部分内存。
Pss(Proportional Set Size):实际使用的物理内存,即:自身应用占有的内存+共享内存中比例分配给这个应用的内存。
通过该程序,每隔 1 秒,获取一次被监控 App 的 Total Pss 值。
使用某个功能(可能会导致 OOM 的那些都要试试),查看 Pss 是否飙升,或者使用过许久都没有降低。
如果使用后飙升并且长时间都降不下来,那就说明肯定会导致 OOM(对象使用过之后还被引用着未释放),如果使用之后 Total Pss 飙升,但是使用过之后能降下来,也可能会导致 OOM,我们还是需要去一点一点排查是什么原因导致的。
如果使用后飙升并且长时间都降不下来,我们就需要 。
此处提到的 Pss,也可以使用 adb 命令
adb shell dumpsys meminfo your packageName
3.内存优化
Android 的虚拟机是基于寄存器的 Dalvik,它的最大堆大小一般比较小(最低端的设备 16M,后来出的设备变成了 24M,48M 等等),因此我们所能利用的内存空间是有限的。如果我们使用内存占用超过了一定的限额后就会出现 OutOfMemory 的错误。
可能会导致内存溢出的情况有以下几种:
对静态变量的错误使用
如果一个变量为 static 变量,它就属于整个类,而不是类的具体实例,所以 static 变量的生命周期是特别的长,如果 static 变量引用了一些资源耗费过多的实例,例如 Context,就有内存溢出的危险。
,专门介绍长时间引用 Context 导致内存溢出的情况。
示例代码:
private static Drawable sB
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView textView = new TextView(this);
textView.setText(&Leaks are bad&);
if (sBackground == null) {
sBackground = getResources().getDrawable(R.drawable.large_bitmap);
textView.setBackgroundDrawable(sBackground);
setContentView(textView);
这种情况下,静态的 sBackground 变量,虽然没有显式的持有 Context 的引用,但当我们执行view.setBackgroundDrawable(Drawable drawable);的时候,drawable 对象会将当前 view 设置为一个回调,通过 View.setCallback(this) 方法。
具体可见 View 类的源码:
public void setBackgroundDrawable(Drawable background) {
if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
mBackground.getMinimumWidth() != background.getMinimumWidth()) {
requestLayout =
background.setCallback(this);
if (background.isStateful()) {
background.setState(getDrawableState());
background.setVisible(getVisibility() == VISIBLE, false);
mBackground =
background.setCallback(this); 代码块就是我们说的设置回调。
所以,这种情况就会存在这么一个隐式的引用链:Drawable 持有 View,而 View 持有 Context,sBackground 是静态的,生命周期特别的长,于是就会导致了 Context 的溢出。
解决办法:
1.不用 activity 的 context 而是用 Application 的 Context;
private static Drawable sB
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView textView = new TextView(this.getApplication());
textView.setText(&Leaks are bad&);
if (sBackground == null) {
sBackground = getResources().getDrawable(R.drawable.large_bitmap);
textView.setBackgroundDrawable(sBackground);
setContentView(textView);
2.在 onDestroy()方法中,解除 Activity 与 Drawable 的绑定关系,从而去除 Drawable 对 Activity 的引用,使 Context 能够被回收;
protected void onDestroy() {
super.onDestroy();
ViewUtils.unbindDrawables(findViewById(android.R.id.content));
System.gc();
public static void unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
if (view instanceof ViewGroup) {
for (int i = 0; i & ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
((ViewGroup) view).removeAllViews();
长周期内部类、匿名内部类长时间持有外部类引用导致相关资源无法释放
长周期内部类、匿名内部类,如 Handler,Thread,AsyncTask 等。
HandlerOutOfMemoryActivity 所示的是 Handler 引发的内存溢出。
ThreadOutOfMemoryActivity 所示的是 Thread 引发的内存溢出。
AsyncTaskOutOfMemoryActivity 所示的时 AsyncTask 引发的内存溢出。
Bitmap 导致的内存溢出
一般是因为尝试加载过大的图片到内存,或者是内存中已经存在的过多的图片,从而导致内存溢出。
数据库 Cursor 未关闭
正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证 Cusor 最终会被释放掉,如果 Cursor 的数据量特表大,特别是如果里面有 Blob 信息时,应该保证 Cursor 占用的内存被及时的释放掉,而不是等待 GC 来处理。
单例模式引用 Context 导致的内存泄露
如果在某个 Activity 中使用 Singleton instance = Singleton.getInstance(this); 就会造成该 Activity 一直被 Singleton 引用着,不能释放。这时候,正确的做法是使用 getApplicationContext() 来替代 Activity 的 Context ,这样就能避免内存泄露。
代码中一些细节
尽量使用 9path
Adapter 要使用 convertView
各种监听,广播等,注册的同时要记得取消注册
使用完对象要及时销毁,能使用局部变量的不要使用全局变量,功能用完成后要去掉对他的引用
切勿在循环调用的地方去产生对象,比如在 getview()里 new OnClicklistener(),这样的话,拖动的时候会 new 大量的对象出来。
使用 Android 推荐的数据结构,比如 HashMap 替换为 SparseArray,避免使用枚举类型(在 Android 平台,枚举类型的内存消耗是 Static 常量的的 2 倍)
使用 lint 工具优化工程
字符串拼接使用 StringBuilder 或者 StringBuffer
尽量使用静态匿名内部类,如果需要对外部类的引用,使用弱引用
for 循环的使用
final int size = array. for(int i = 0; i&i++)
for(int i =0;i & array.i++)
最后,整理了一些开发中可能会导致内存溢出的场景,放在 com.cundong.memory.demo.wrong 中,并且给出了优化方法,放在 com.cundong.memory.demo.right 中。

我要回帖

更多关于 luamemorymonitor 的文章

 

随机推荐