Android内存管理机制与分析工具

在 android 系统中有个垃圾内存回收机制,在虚拟机层自动分配和释放内存,因此不需要在代码中分配和释放某一块内存,从应用层面上不容易出现内存泄漏和内存溢出等问题,但是需要内存管理。android 系统在内存管理上有一个 generational heap memory 模型,内存回收的大部分压力不需要应用层关心, generational heap memory 有自己一套管理机制,当内存达到一个阈值时,系统会根据不同的规则自动释放系统认为可以释放的内存,也正是因为 android 程序把内存控制的权力交给了 generational heap memory,一旦出现内存泄漏和溢出方面的问题,排查错误将会成为一项异常艰难的工作。除此之外,部分 android 应用开发人员在开发过程中并没有特别关注内存的合理使用,也没有在内存方面做太多的优化,当应用程序同时运行越来越多的任务,加上越来越复杂的业务需求时,完全依赖 android 的内存管理机制就会导致一系列性能问题逐渐呈现,对应用的稳定性和性能带来不可忽视的影响,因此,解决内存问题和合理优化内存是非常有必要的。
android内存管理机制
android 应用都是在 android 的虚拟机上运行,应用 程序的内存分配与垃圾回收都是由虚拟机完成的。在 android 系统,虚拟机有两种运行模式:dalvik 和 art。
1、java对象生命周期
一般java对象在虚拟机上有7个运行阶段:
创建阶段->应用阶段->不可见阶段->不可达阶段->收集阶段->终结阶段->对象空间重新分配阶段
2、内存分配
在 android 系统中,内存分配实际上是对堆的分配和释放。当一个 android 程序启动,应用进程都是从一个叫做 zygote 的进程衍生出来,系统启动 zygote 进程后,为了启动一个新的应用程序进程,系统会衍生 zygote 进程生成一个新的进程,然后在新的进程中加载并运行应用程序的代码。其中,大多数的 ram pages 被用来分配给framework 代码,同时促使 ram 资源能够在应用所有进程之间共享。
但是为了整个系统的内存控制需要,android 系统会为每一个应用程序都设置一个硬性的 dalvik heap size 最大限制阈值,整个阈值在不同设备上会因为 ram 大小不同而有所差异。如果应用占用内存空间已经接近整个阈值时,再尝试分配内存的话,就很容易引起内存溢出的错误。
3、内存回收机制
我们需要知道的是,在 java 中内存被分为三个区域:young generation(年轻代)、old generation(年老代)、permanent generation(持久代)。最近分配的对象会存放在 young generation 区域。对象在某个时机触发 gc 回收垃圾,而没有回收的就根据不同规则,有可能被移动到 old generation,最后累积一定时间在移动到 permanent generation 区域。系统会根据内存中不同的内存数据类型分别执行不同的 gc 操作。gc 通过确定对象是否被活动对象引用来确定是否收集对象,进而动态回收无任何引用的对象占据的内存空间。但需要注意的是频繁的 gc 会增加应用的卡顿情况,影响应用的流畅性,因此需要尽量减少系统 gc 行为,以便提高应用的流畅度,减小卡顿发生的概率。
内存分析工具
做内存优化前,需要了解当前应用的内存使用现状,通过现状去分析哪些数据类型有问题,各种类型的分布情况如何,以及在发现问题后如何发现是哪些具体对象导致的,这就需要相关工具来帮助我们。
1、memory monitor
memory monitor 是一款使用非常简单的图形化工具,可以很好地监控系统或应用的内存使用情况,主要有以下功能:
显示可用和已用内存,并且以时间为维度实时反应内存分配和回收情况。
快速判断应用程序的运行缓慢是否由于过度的内存回收导致。
快速判断应用是否由于内存不足导致程序崩溃。
2、heap viewer
heap viewer 的主要功能是查看不同数据类型在内存中的使用情况,可以看到当前进程中的 heap size 的情况,分别有哪些类型的数据,以及各种类型数据占比情况。通过分析这些数据来找到大的内存对象,再进一步分析这些大对象,进而通过优化减少内存开销,也可以通过数据的变化发现内存泄漏。
3、allocation tracker
memory monitor 和 heap viewer 都可以很直观且实时地监控内存使用情况,还能发现内存问题,但发现内存问题后不能再进一步找到原因,或者发现一块异常内存,但不能区别是否正常,同时在发现问题后,也不能定位到具体的类和方法。这时就需要使用另一个内存分析工具 allocation tracker,进行更详细的分析, allocation tracker 可以分配跟踪记录应用程序的内存分配,并列出了它们的调用堆栈,可以查看所有对象内存分配的周期。
4、memory analyzer tool(mat)
mat 是一个快速,功能丰富的 java heap 分析工具,通过分析 java 进程的内存快照 hprof 分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被垃圾收集器回收,并可以通过视图直观地查看可能造成这种结果的对象。
常见内存泄漏场景
如果在内存泄漏发生后再去找原因并修复会增加开发的成本,最好在编写代码时就能够很好地考虑内存问题,写出更高质量的代码,这里列出一些常见的内存泄漏场景,在以后的开发过程中需要避免这类问题。
资源性对象未关闭。比如cursor、file文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。
注册对象未注销。比如事件注册后未注销,会导致观察者列表中维持着对象的引用。
类的静态变量持有大数据对象。
非静态内部类的静态实例。
handler临时性内存泄漏。如果handler是非静态的,容易导致 activity 或 service 不会被回收。
容器中的对象没清理造成的内存泄漏。
webview。webview 存在着内存泄漏的问题,在应用中只要使用一次 webview,内存就不会被释放掉。
除此之外,内存泄漏可监控,常见的就是用leakcanary 第三方库,这是一个检测内存泄漏的开源库,使用非常简单,可以在发生内存泄漏时告警,并且生成 leak tarce 分析泄漏位置,同时可以提供 dump 文件进行分析。
优化内存空间
没有内存泄漏,并不意味着内存就不需要优化,在移动设备上,由于物理设备的存储空间有限,android 系统对每个应用进程也都分配了有限的堆内存,因此使用最小内存对象或者资源可以减小内存开销,同时让gc 能更高效地回收不再需要使用的对象,让应用堆内存保持充足的可用内存,使应用更稳定高效地运行。
常见做法如下:
对象引用。强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。
减少不必要的内存开销。注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、bitmap对象的复用。
使用最优的数据类型。比如针对数据类容器结构,可以使用arraymap数据结构,避免使用枚举类型,使用缓存lrucache等等。
图片内存优化。可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。

虹科自动驾驶研发公司成立,将于9号亮相上海汽车测试展!
风扇调速电路
阿里平头哥开源MCU设计平台 芯片设计该如何寻求客制化与标准化的平衡
天文学家利用人工智能收集的数据发现两个隐藏的刨床
小米6或在延期,大屏版5.7寸屏,蔡司双摄,或取消Home键
Android内存管理机制与分析工具
逐点比较法
华为智能手机应选择什么样的快充便携充电宝?
昇腾910和含光800性能对比
交换机与路由器二三层转发原理
“两会”4G受热议 论光纤光缆行业机会
可穿戴式设计中实现超低功耗的3大要诀
碳化硅和igbt器件未来应用前景分析
Mouser备货Analog Devices ADSP-CM40x 240MHz混合信号开发板
超声波采集技术 指纹采集技术
QorIQ Layerscape技术易于软件移植和使用
剩余电流动作继电器在电动伸缩门的应用
“可交互空中成像”技术车内应用详解
同茂线性马达分享新闻之澳洲将拍卖机器人打造的建筑
什么是DTC快照信息