[TOC]

文章参考:

概述

内存问题分析

查看App的内存限制

1
adb shell cat /system/build.prop

输出结果可能如下:

image-20230130231750862

内存管理

adj管理算法

通过打分机制,通过APP的状态,进行打分。如果分数越高,则应用则越有可能被kill掉。APP使用的内存越大或者越多,则APP越有可能被Kill掉。

五个等级:

前台进程

可见进程

服务进程

空进程

这里也就涉及到进程保活的相关逻辑,这里不再赘述。

image-20230130233501055

内存优化方案

1.Android内存管理机制

Android应用都是在Android虚拟机上运行的,内存分配和垃圾回收都是由Android虚拟机来完成的。

2.常见的内存泄漏

其实内存泄漏的本质就是较长生命周期的对象引用了较短生命周期的对象。

2.1 内存泄露

内存泄漏原因:堆上分配的对象已经不会再使用,但是GC收集器无法对其进行回收,此对象被强应用所引用 。

  • 静态变量导致的内存泄漏

    解决办法:将内部类设为静态内部类或独立出来;使用context.getApplicationContext()。

  • 单例模式导致的内存泄漏

    解决办法:传参context.getApplicationContext()。

  • 属性动画导致的内存泄漏

    解决办法:在Activity.onDestroy()中调用Animator.cancel()停止动画。

  • Handler导致的内存泄漏

    解决办法:使用静态内部类+WeakReference弱引用;当外部类结束生命周期时清空消息队列。

  • 线程导致的内存泄漏

    解决办法:将AsyncTask和Runnable设为静态内部类或独立出来;在线程内部采用弱引用保存Context引用。

  • 资源未关闭导致的内存泄漏

    解决办法:在Activity销毁的时候要及时关闭或者注销。例如:

    ① BraodcastReceiver:调用unregisterReceiver()注销;

    ②Cursor,Stream、File:调用close()关闭;

    ③Bitmap:调用recycle()释放内存(2.3版本后无需手动)。

  • Adapter导致的内存泄漏

    详情:不使用缓存而只依靠getView() 每次重新实例化Item,会给gc制造压力。

    解决办法:在构造Adapter时使用缓存的convertView。

  • WebView导致的内存泄漏。

    详情:WebView比较特殊,即使是调用了它的destroy方法,依然会导致内存泄漏。

    解决办法:其实避免WebView导致内存泄漏的最好方法就是让WebView所在的Activity处于另一个进程中,当这个Activity结束时杀死当前WebView所处的进程即可,我记得阿里钉钉的WebView就是另外开启的一个进程,应该也是采用这种方法避免内存泄漏。

  • 集合类泄漏

    详情:比如全局map等有静态应用,最后没有做删除。

    解决办法:在onDestry时回收不需要的集合。

2.2 扩大内存

大厂的SDK可能内存泄漏会少一些,但一些小厂的SDK质量也就不太靠谱一些。那应对这种我们无法改变的情况,最好的办法就是扩大内存。

扩大内存通常有两种方法:

  • 一个是在清单文件中的Application下添加largeHeap=”true”这个属性,另一个就是同一个应用开启多个进程来扩大一个应用的总内存空间。
  • 第二种方法其实就很常见了,比方说我使用过个推的SDK,个推的Service其实就是处在另外一个单独的进程中。
  • Android中的内存优化总的来说就是开源和节流,开源就是扩大内存,节流就是避免内存泄漏。

2.3 检测、分析内存泄漏的工具

  • MemoryMonitor:随时间变化,内存占用的变化情况
  • MAT:输入HRPOF文件,输出分析结果
  • a. Histogram:查看不同类型对象及其大小
  • b.DominateTree:对象占用内存及其引用关系
  • c.MAT使用教程
  • LeakCanary:实时监测内存泄漏的库(LeakCanary原理)