Potato
Potato copied to clipboard
Android Memory Optimization
Android Memory Optimization
[TOC]
这篇文章来讲解 Android 中涉及的内存优化, 尤其是 内存泄漏。
基础知识
- 通过 shell 命令可以分析内存状况。
- dvm 最大可用内存:
adb shell getprop | grep dalvik.vm.heapsize
- 单个程序限制最大可用内存:
adb shell getprop | grep headp growth limit
- 输出 App 内存使用情况概览:
adb shell dumpsys meminfo
- dvm 最大可用内存:
- MAT 工具的使用
内存优化
内存不优化的结果
- 程序频繁发生 GC, 造成内存抖动,应用卡顿。
- 程序异常,闪退或者 ANR,进程被杀死
- 内存泄漏,导致内存分配异常,进程被杀死。
常见的内存优化的点
- 只需要 UI 提供一套高分辨率的图片,放在
drawable-xxhdpi
, 这样低分辨率设备中大小压缩, 不会增大内存。如果不需要缩放,则放在drawable-nohdpi
文件夹下。 - 图片优化
- 颜色模式 RGB_8888 -> RGB_565
- 降低大小,降低采样率
- 在 APp 退到后台,内存紧张即将被 kill 时重写 onTrimMemory() 方法释放不需要内存,放置进程被杀。
- 在 RecyclerView 中,因为被回收不可见时,第一选择放进 mCacheView 中,这里 Item 被复用并不会 bindViewHolder 来重新绑定数据,只有被回收进 mRecyclePool 中后拿出来复用才会重新绑定数据,因此重写 Recycler.Adapter 中的 onViewRecycled() 方法来使 item 被回收进 RecyclerPool 的时候释放图片饮用
- 集合优化: 使用 SparseArray, SparseBooleanArray 等 Android 特有的数据结构。
- 避免创作不必要的对象:for 循环中,字符串拼接等。
- 适当采用弱引用和软引用。
- 使用基本数据类型而不是其包装类型,使用内存缓存和词牌你缓存
- 降低运行时内存:减少 apk 体积,去除无用的代码和资源,复用资源,压缩图片。
内存泄漏
如何检测
- shell 命令 + LeakCanary + MAT(事件充足):运行程序,所有功能跑一遍,完全退出程序,手动触发 GC。然后使用 adb shell dumpsys meminfo packagename -d 命令查看退出界面后 Objects 下的 Views 和 Activites 是否为0,如果不是则通过 LeakCanary 检查可能存在内存泄漏的地方,并通过 MAT 分析。
- Profile MEMORY(时间有限时使用):运行程序,对每一个页面进行内存分析检查。首先,反复打开关闭页面多次,触发 GC。如果此时 total 内存没有恢复到之前的数值,则表示可能发生内存泄漏。此时再点击 heap dump 按钮查看当前的内存堆栈情况,找到当前 Activity。
本质
无法回收无用的对象
- Activity的泄漏:finish后,引用activity的对象未释放,context被使用泄漏
常见内存泄漏案例
- 单例造成的内存泄漏:使用 application context
- 非静态内部类创建静态实例(因为持有外部类的引用)。将该类设置为静态内部类或者抽出为单例,使用 application context。(后续会从 java 和 kotlin 的字节码进行分析)
- Handler 造成的内存的泄漏。(与上面差不多)
- 线程造成:Activity 关闭之后线程还在执行。
- 资源使用结束及时关闭。