Android内存优化之OOM篇

" 记录Android内存优化及内存泄露解决方案..."

Posted by RyanYans on March 15, 2017

本文记录的是我对 Android 内存优化探索与理解。

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的错误。

内存泄漏的产生原因

  1. 加载对象过大
  2. 相应资源过多,来不及加载
  3. 数据库的cursor没有关闭
  4. 构造adapter没有使用缓存contentview
  5. 调用registerReceiver()后未调用unregisterReceiver()
  6. 未关闭I/O流
  7. Context泄漏
  8. static关键字 ….

内存泄露解决方案

  1. 内存引用上做些处理,比如使用软引用
  2. 内存在加载图片时做好图片边界压缩、缓存处理
  3. 加载图片推荐使用Glide/Fresco等开源库
  4. 避免在Android中使用Enum
  5. 优化Delivk虚拟机的堆内存分配
  6. 减少Bitmap对象的内存占用,Bitmap消耗内存的大胖子,减少创建出来的Bitmap的内存占用很重要。
  7. 使用更加轻量的数据结构如ArrayMap代替HashMap。后者专为移动系统设计,占内存更少,因为HashMap需要一个额外的实例对象来记录Mapping的操作。而SparesArray高效的避免了key和value的自动装箱,而且避免了装箱后的解箱。

内存泄漏的发现

说了这么多 现在该说我们 内存泄露检测神器了! 内存泄漏的分析的话,必须使用工具才行,庆幸的是,各路大神已经给我们提供了很多强大的内存分析工具,我这里只会讲最方便的。这里提供几个套餐供选择:

套餐一:Studio自带Heap Viewer

想不想知道你的应用到底有没有内存泄漏呢?说真,就一分钟的事,毕竟Studio牛逼着呢~

  1. 打开Studio,连上你的应用,然后Android Monitor (1)->Monitors(2)->Memory,上面有四个图标,暂停图标是开启内存使用状态追踪的开关,默认是开启的,小车图标就是手动GC(3),向下箭头图标(4)是查看堆的分配情况,最后的图标allocation tracker用来跟踪内存分配情况。

  2. 我讲一下我的使用方式,在应用中操作,从activity1跳转到activity2,然后跳回到activity1界面,这样是为了分析activity2是否会产生内存泄漏。接下来就是真刀真枪的干了。

  3. 点击小车图标(3),手动GC进行垃圾回收,这样才能更准确的判断activity2是否有内存泄漏发生,最后点击向下箭头图标(4),Studio会自动生成hprof文件并自动展示在Studio界面中。

Step1

  1. 这个就是内存的分析文件了,点击Analyzer Tasks(5),做这步的原因是啥呢,因为我懒啊,这是让Studio帮我们自动分析是否出现内存泄漏。

Step2

  1. 勾上Detect Leaked Activities(6),最后运行(7)就出现分析结果了

Step3

  1. 看到没,activity2出现内存泄漏了麻蛋(8),补充一句,我这是拿真实的项目进行演示的,左下角是引用树(9),通过引用树就可以定位到内存泄漏的具体信息了。

Step4

套餐二:MAT

这里一篇官文,自行研究研究。因为我一般不用,不要问为什么,因为用起来比较麻烦一些。

MAT(Memory Analyzer)内存分析工具

套餐三:内存泄露检测神器 LeakCanary

LeakCanary是Square公司推出的内存泄露检测工具,其实Square公司对开源的贡献还是挺大的 就Android而言 比如:

图片开源框架Picasso:https://github.com/square/picasso 网络请求框架Retrofit:https://github.com/square/retrofit 。。。。

今天我们就说说 LeakCanary!

  1. 首先,在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’ }

  2. 第二步,在你的全局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...
         }
     }
    
  3. 最后在Menifest清单文件下配置Application

Step5

然后,就没有然后了。。

4.打开你的App就会附上一个App

S70321-203049(1)(1).jpg

5.通过这个泄漏路径,就对应进行内存泄漏的原因进行分析了,你也可以通过输出的日志进行内存泄漏的定位了!

S70321-20370466.jpg

内存优化还有很多内容,造成内存泄露也有很多千奇百怪原因,这也只能就靠慢慢脱坑了。


学习笔记,如有谬误,敬请指正。