Potato icon indicating copy to clipboard operation
Potato copied to clipboard

Android Memory Optimization

Open yunshuipiao opened this issue 5 years ago • 0 comments

Android Memory Optimization

[TOC]

这篇文章来讲解 Android 中涉及的内存优化, 尤其是 内存泄漏。

基础知识

  1. 通过 shell 命令可以分析内存状况。
    • dvm 最大可用内存: adb shell getprop | grep dalvik.vm.heapsize
    • 单个程序限制最大可用内存: adb shell getprop | grep headp growth limit
    • 输出 App 内存使用情况概览:adb shell dumpsys meminfo
  2. MAT 工具的使用

内存优化

内存不优化的结果

  1. 程序频繁发生 GC, 造成内存抖动,应用卡顿。
  2. 程序异常,闪退或者 ANR,进程被杀死
  3. 内存泄漏,导致内存分配异常,进程被杀死。

常见的内存优化的点

  1. 只需要 UI 提供一套高分辨率的图片,放在 drawable-xxhdpi, 这样低分辨率设备中大小压缩, 不会增大内存。如果不需要缩放,则放在 drawable-nohdpi文件夹下。
  2. 图片优化
    • 颜色模式 RGB_8888 -> RGB_565
    • 降低大小,降低采样率
  3. 在 APp 退到后台,内存紧张即将被 kill 时重写 onTrimMemory() 方法释放不需要内存,放置进程被杀。
  4. 在 RecyclerView 中,因为被回收不可见时,第一选择放进 mCacheView 中,这里 Item 被复用并不会 bindViewHolder 来重新绑定数据,只有被回收进 mRecyclePool 中后拿出来复用才会重新绑定数据,因此重写 Recycler.Adapter 中的 onViewRecycled() 方法来使 item 被回收进 RecyclerPool 的时候释放图片饮用
  5. 集合优化: 使用 SparseArray, SparseBooleanArray 等 Android 特有的数据结构。
  6. 避免创作不必要的对象:for 循环中,字符串拼接等。
  7. 适当采用弱引用和软引用。
  8. 使用基本数据类型而不是其包装类型,使用内存缓存和词牌你缓存
  9. 降低运行时内存:减少 apk 体积,去除无用的代码和资源,复用资源,压缩图片。

内存泄漏

如何检测

  1. shell 命令 + LeakCanary + MAT(事件充足):运行程序,所有功能跑一遍,完全退出程序,手动触发 GC。然后使用 adb shell dumpsys meminfo packagename -d 命令查看退出界面后 Objects 下的 Views 和 Activites 是否为0,如果不是则通过 LeakCanary 检查可能存在内存泄漏的地方,并通过 MAT 分析。
  2. Profile MEMORY(时间有限时使用):运行程序,对每一个页面进行内存分析检查。首先,反复打开关闭页面多次,触发 GC。如果此时 total 内存没有恢复到之前的数值,则表示可能发生内存泄漏。此时再点击 heap dump 按钮查看当前的内存堆栈情况,找到当前 Activity。

本质

无法回收无用的对象

  • Activity的泄漏:finish后,引用activity的对象未释放,context被使用泄漏

常见内存泄漏案例

  1. 单例造成的内存泄漏:使用 application context
  2. 非静态内部类创建静态实例(因为持有外部类的引用)。将该类设置为静态内部类或者抽出为单例,使用 application context。(后续会从 java 和 kotlin 的字节码进行分析)
  3. Handler 造成的内存的泄漏。(与上面差不多)
  4. 线程造成:Activity 关闭之后线程还在执行。
  5. 资源使用结束及时关闭。

yunshuipiao avatar May 14 '19 09:05 yunshuipiao