本文记录的是我对 Android 内存优化探索与理解。
Android内存管理机制
官方文档有一篇文章
Android系统的Dalvik虚拟机扮演了内存垃圾自动回收的角色。
OOM介绍(out of memory 内存溢出)
Android内存优化是性能优化很重要的一部分,而如何避免OOM又是内存优化的核心。
有必要讲一下Android中的垃圾收集是怎么进行的,Android中使用标记-清除(Mark-Sweep)算法进行垃圾回收(garbage collection,简称GC),就是按照正常套路来说,在坑位(内存)不够的情况下,垃圾收集器会遍历全部对象,看哪些对象是可以被回收掉腾出内存的,这个过程称为Mark(标记),Mark的时候要求除了垃圾收集线程之外,其它的线程都停止,这种吊炸天的现象在垃圾收集算法中称为Stop The World,世界围着他转,这就造成了我们的程序会卡顿,但是一般情况下这个时间就几十毫秒,我根本就感受不到好吗。Mark完之后,就是释放内存空间啦,这个过程称为Sweep(清除)。然而,当GC后内存好不足以分配时,就会引起outofmemoryError的错误。
内存泄漏的产生原因
- 加载对象过大
- 相应资源过多,来不及加载
- 数据库的cursor没有关闭
- 构造adapter没有使用缓存contentview
- 调用registerReceiver()后未调用unregisterReceiver()
- 未关闭I/O流
- Context泄漏
- static关键字 ….
内存泄露解决方案
- 内存引用上做些处理,比如使用软引用
- 内存在加载图片时做好图片边界压缩、缓存处理
- 加载图片推荐使用Glide/Fresco等开源库
- 避免在Android中使用Enum
- 优化Delivk虚拟机的堆内存分配
- 减少Bitmap对象的内存占用,Bitmap消耗内存的大胖子,减少创建出来的Bitmap的内存占用很重要。
- 使用更加轻量的数据结构如ArrayMap代替HashMap。后者专为移动系统设计,占内存更少,因为HashMap需要一个额外的实例对象来记录Mapping的操作。而SparesArray高效的避免了key和value的自动装箱,而且避免了装箱后的解箱。
内存泄漏的发现
说了这么多 现在该说我们 内存泄露检测神器了! 内存泄漏的分析的话,必须使用工具才行,庆幸的是,各路大神已经给我们提供了很多强大的内存分析工具,我这里只会讲最方便的。这里提供几个套餐供选择:
套餐一:Studio自带Heap Viewer
想不想知道你的应用到底有没有内存泄漏呢?说真,就一分钟的事,毕竟Studio牛逼着呢~
-
打开Studio,连上你的应用,然后Android Monitor (1)->Monitors(2)->Memory,上面有四个图标,暂停图标是开启内存使用状态追踪的开关,默认是开启的,小车图标就是手动GC(3),向下箭头图标(4)是查看堆的分配情况,最后的图标allocation tracker用来跟踪内存分配情况。
-
我讲一下我的使用方式,在应用中操作,从activity1跳转到activity2,然后跳回到activity1界面,这样是为了分析activity2是否会产生内存泄漏。接下来就是真刀真枪的干了。
-
点击小车图标(3),手动GC进行垃圾回收,这样才能更准确的判断activity2是否有内存泄漏发生,最后点击向下箭头图标(4),Studio会自动生成hprof文件并自动展示在Studio界面中。
- 这个就是内存的分析文件了,点击Analyzer Tasks(5),做这步的原因是啥呢,因为我懒啊,这是让Studio帮我们自动分析是否出现内存泄漏。
- 勾上Detect Leaked Activities(6),最后运行(7)就出现分析结果了
- 看到没,activity2出现内存泄漏了麻蛋(8),补充一句,我这是拿真实的项目进行演示的,左下角是引用树(9),通过引用树就可以定位到内存泄漏的具体信息了。
套餐二:MAT
这里一篇官文,自行研究研究。因为我一般不用,不要问为什么,因为用起来比较麻烦一些。
套餐三:内存泄露检测神器 LeakCanary
LeakCanary是Square公司推出的内存泄露检测工具,其实Square公司对开源的贡献还是挺大的 就Android而言 比如:
图片开源框架Picasso:https://github.com/square/picasso 网络请求框架Retrofit:https://github.com/square/retrofit 。。。。
今天我们就说说 LeakCanary!
-
首先,在app的
build.gradle
文件下添加依赖,老生常谈不解释。 dependencies { debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.5’ releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5’ testCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5’ } -
第二步,在你的全局Application中的onCreate()方法中进行初始化
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } LeakCanary.install(this); // Normal app init code... } }
-
最后在Menifest清单文件下配置Application
然后,就没有然后了。。
4.打开你的App就会附上一个App
5.通过这个泄漏路径,就对应进行内存泄漏的原因进行分析了,你也可以通过输出的日志进行内存泄漏的定位了!
内存优化还有很多内容,造成内存泄露也有很多千奇百怪原因,这也只能就靠慢慢脱坑了。