- 内存优化介绍
- 内存是大问题但缺乏关注
- 压死骆驼的最后一根稻草
- 内存问题
- 内存抖动:锯齿状、GC导致卡顿
- 内存泄漏:可用内存减少、频繁GC
- 内存溢出:OOM、程序异常
- 优化工具选择
- Memory Profiler
- 实时图标展示应用内存使用量
- 识别内存泄漏、抖动等
- 提供捕获堆转储、强制GC以及跟踪内存分配的能力
- 方便直观、线下平时使用
- Memory Analyzer
- 强大的Java Heap分析工具,查找内存泄漏及内存占用
- 生成整体报告、分析问题等
- 线下深入使用
- LeakCanary
- 自动内存泄漏检测
- https://github.com/square/leakcanary
- 线下集成
- Memory Profiler
-
Java内存管理机制
-
Java内存分配
- 方法区、虚拟机栈、本地方法栈、堆、程序计数器
-
Java内存回收算法
-
标记-清除算法
效率和清除效率不高
产生大量不连续的内存碎片
- 标记出所有需要回收的对象
- 统一回收所有被标记的对象
-
复制算法
实现简单,运行高效
浪费一半空间,代价大
- 将内存划分为大小相等的两块
- 一块内存用完之后复制存活对象到另一块
- 清理另一块内存
-
标记-整理算法
- 标记过程与“标记-清除”算法一样
- 存活对象往一端进行移动
- 清理其余内存
-
分代收集算法
- 结合多种收集算法优势
- 新生代对象存活率低,复制
- 老年代对象存活率高,标记-整理
-
-
-
Android内存管理机制
内存弹性分配,分配值与最大值受具体设备影响
OOM场景:内存真正不足、可用内存不足
- Dalvik与Art区别
- Dalvik仅固定一种回收算法
- Art回收算法可运行期选择
- Art具备内存整理能力,减少内存空洞
- Low Memory Killer
- 进程分类
- 回收收益
- Dalvik与Art区别
-
内存抖动介绍
定义:内存频繁分配和回收导致内存不稳定
表现:频繁GC、内存曲线呈锯齿状
危害:导致卡顿、OOM
内存抖动导致OOM:
- 频繁创建对象,导致内存不足及碎片
- 不连续的内存片无法被分配,导致OOM
-
内存抖动解决实战
- 使用Memory Profiler初步排查
- 使用Memory Profiler或CPU Profiler结合代码排查
- 模拟内存抖动代码见:MemoryShakeActivity
-
内存抖动解决技巧
找循环或者频繁调用的地方
-
内存泄漏介绍
定义:内存中存在已经没有用的对象
表现:内存抖动、可用内存逐渐变少
危害:内存不足、GC频繁、OOM
-
Memory Analyzer
- http://www.eclipse.org/mat/downloads.php
- 转换:hprof-conv原文件路径转换后文件路径
- 模拟内存泄露代码见:MemoryLeakActivity
-
内存泄漏解决实战
- 使用Memory Profiler初步观察
- 使用Memory Analyzer结合代码确认
- 找到内存泄露位置
-
Bitmap内存模型
- API10之前Bitmap自身在Dalvik Heap中,像素在Native
- API10之后像素也被放在Dalvik Heap中
- API26之后像素在Native
-
获取Bitmap占用内存
- getByteCount
- 宽 * 高 * 一像素占用内存
-
常规方式
- 背景:图片对内存优化至关重要、图片宽高大于控件宽高
- 实现:集成ImageView,覆写实现计算大小
- 侵入性强
- 不通用
-
ARTHook实战
-
挂钩,将额外的代码钩住原有方法,修改执行逻辑
- 运行时插桩
- 性能分析
-
Epic简介
- Epic是一个虚拟机层面、以Java Method为粒度的运行时Hook框架
- 支持Android4.0 - 9.0
- https://github.com/tiann/epic
-
Epic实战
-
ImageHook.java
-
DexposedBridge.hookAllConstructors(ImageView.class, new XC_MethodHook() { @Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); DexposedBridge.findAndHookMethod(ImageView.class, "setImageBitmap", Bitmap.class, new ImageHook()); } });
-
ARTHook 无侵入性,通用性强,兼容问题大,开源方案不能带到线上环境
-
- 常规方式
- 设定场景线上Dump:
Debug.dumpHprofData()
- 超过最大内存80%线上Dump,回传文件,分析
- Dump文件太大,和对象数正相关,可裁剪
- 上传失败率高、分析困难
- 配合一定策略,有一定效果
- 设定场景线上Dump:
- LeakCanary
- LeakCanary带到线上
- 预设泄漏怀疑点
- 发现泄漏回传
- 不适合所有情况,必须预设坏一点
- 分析比较耗时、也容易OOM
- LeakCanary原理
- 监控生命周期,onDestory添加RefWatcher检测
- 二次确认断定发生内存泄漏
- 分析泄漏,找引用链
- 监控组件+分析组件
- LeakCanary定制
- 预设怀疑点:自动找怀疑点
- 分析泄漏链路慢:分析Retain size大的对象
- 分析OOM:对象裁剪,不全部加载到内存
- 线上监控完整方案
- 待机内存、重点模块内存、OOM率
- 整体及重点模块GC次数、GC时间
- 增强的LeakCanary自动化内存泄漏分析
- 优化大方向
- 内存泄漏
- 内存抖动
- Bitmap
- 优化细节
- LargeHeap属性
- onTrimMemory:系统低内存回调
- 使用优化过的集合:SparseArray
- 谨慎使用Shared Preference
- 谨慎使用外部库
- 业务架构设计合理
- 你们内存优化项目的过程是怎么做的
- 分析现状、确认问题
- 线上OOM率
- AS 内存监控抖动频繁
- 针对性优化
- 分析现状、确认问题
- 你做了内存优化最大的感受是什么
- 磨刀不误砍柴工
- 技术优化必须结合业务代码
- 系统化完善解决方案
- 如何检测所有不合理的地方
- ARTHook
- 重点强调区别