序
Android的性能优化几乎是面试必考题 ,答案的结构很唯一无非就是内存优化 、卡顿优化 、I/O优化 、UI优化 、启动优化 、储存优化 、闪退优化 、网络优化 、耗电优化 、包体积优化等等 。但是面试的时候只要把任意一个结构突突的很透彻 ,当前的Offer已经成了一半了 ;如果可以把常用的内存优化 、卡顿优化 、I/O 优化 、启动优化突突的很透彻 ,Offer已经成了 ;要是在加上一些储存 、闪退 、网络 、包体积的话 ,就可以主动地谈薪资(有一个情况可能不太行 ,就是公司的需求是写代码的 ,对技术要求无的)。
PS:会一直更新这个系列 。
「 内存优化 」、「 卡顿优化 」、「 I/O优化 」
「 UI 优化 」、 「 启动优化 」、「 储存优化 」
「 闪退优化 」、「 网络优化 」、「 耗电优化 」
「 包体积优化 」。
《题外话:之前我建个技术群 ,一直聊得挺可以的 ,这几天突突的有几个25K 以上Offer的小伙伴 ,搞得我很自闭呀 。》
Android性能优化系列第一篇 内存优化 Bitmap
前言
内存优化是性能优化和工作项目中优化比较重要的一个点,主要包含两个方向。
1. RAM优化 ,即降低运行时内存 。这里的目的是防止程序发生 OOM 异常 ,以及降低程序由于内存过大被LMK机制杀死的概率 。另一方面 ,不合理的内存使用会使GC大大增多 ,从而导致程序变卡 。
2. 优化ROM ,即降低程序占ROM的体积 。这里主要是为了降低程序占用的空间 ,防止由于ROM空间不足导致程序无法安装 。
Bitmap优化主要属于第一种 。
我们常说的内存到底会发现什么问题 ?两个问题
1. 异常 。崩溃时候的 "异常率" ,异常包括 OOM 、内存分配失败这些崩溃 ,也包括整体内存不足应用被杀死 、设备重启等问题 。
2. 卡顿 。Java内存不足会导致频繁 GC ,这个问题在Dalvik虚拟机上会更加明显 ,而ART虚拟机在内存管理跟回收方面有很大的优化 ,内存分配和GC效率相比提升了 5~10 倍 。
Bitmap优化
Bitmap内存一般占应用总内存很大一部分 。即使把所有的 Bitmap 都放在 Natice 内存中 ,并不代表内存问题就完全解决了 ,这样做只是提升了系统内存利用率减少GC带来的一些问题 ,但是并不能就解决 Bitmap 占用内存大的问题 。
Bitmap介绍
Android Bitmap是属于加载图片的类 ,图片数据一般来说所占内存比较大 ,而 Android 将他们划分为两部分图片信息和像素点数据 ,信息放在 Dalvik heap 中 ,像素点会根据不同的 Android 系统存在不同的位置。
Android2.3.3(API10)之前
bitmap对象和对象里对应的像素数据是分开存储的 ,bitmap 存在J ava Heap 中 ,而像素数据存储在 native heap 中。
Android3.0 (API11) - Android7.1(API25)
Bitmap对象以及其像素数据存放在 Java Heap 中 。
Android8.0(API26)之后
Bitmap存在 Java Heap 中 ,而像素数据存储在 native heap 中 。
优化策略
1. 统一图片库
图片内存优化的前提是收拢图片的调用 ,这样我们可以做整体的控制策略 。例如低端机使用565格式 、更加严格的缩放算法 ,可以使用 Glide、Fresco 或者自研都可以 。
2. 统一监控
大图片监控 。在我们的开发的过程中 ,我们需要注意某张图片内存是否占用过大 ,例如长宽远大于 View 甚至屏幕的长宽 。如果检测到不合规的图片使用 ,应该立即弹出对话框提示图片所在的Activity和堆栈 ,快速的定位并解决问题 。在灰度和线上环境下可以将异常信息上报到后台 ,我们可以计算有多少比例的图片会超过屏幕的大小 ,也就是图片的 "超宽率" 。
重复图片监控 。重复图片指的是 Bitmap 像素数据完全一致 ,但是有多个不同的对象存在 。这个监控不需要太多的样本量 ,一般只在内部使用 。这个可以细聊 ,我写过这个 Demo 。
图片总内存 。通过收拢图片使用 ,我们还可以统计应用所有图片占用的内存 ,这样在线上就可以按不用的系统 、屏幕分辨率等维度去分析图片内存的占用情况 。在 OOM 崩溃的时候 ,也可以把图片占用的内存 、Top N 图片的内存写到崩溃日志中 ,帮助我们排查问题 。
待续 。。。
重复图片监控 Demo SuperTest
背景:一个项目中的多个 Bitmap 像素数据完全一致 ,但是有对象地址不一样 。
目标:实现一个工具 ,自动打印出重复 Bitmap 的图片和引用链 。跟我们使用的 LeakCanary 的调用链一样 ,定位到那个对象泄漏 ,然后把这个对象的调用链一层一层打印出来 。 如下图所示:
涉及到的技术点:Squre 公司出的 HaHa 库用来分析 hprof 文件 自动分析Android堆转储 、生成 dump 文件(使用HaHa库) 、堆转储文件 hprof 。
流程:首先通过 HaHa 库生成堆转储文件 ,然后在打开这个堆转存 hprof 文件 ;通过 Snapshot 获得 Bitmap Class 和 app heap 、default heap ;从 heap 中获取所有 Bitmap 实例再从 Bitmap 获取所有 buffer 数组 ,最后判断这些 mBuffer 的hash值是否是重复的 。通俗的讲就是如果一个本地图片生成了多个实例对象 ,我们可以通过这些实例在 heap 中的buffer hash 值进行判断是否是重复的 Bitmap ,如果重复的话在使用 LeakCanary 查找内存泄漏调用链的漏记吧对应的调用打印出来。
PS :名词解释
HaHa 库:HaHa 库是用来生成和分析 Android 堆转储文件的 ;堆转储的意思就是将 Java 堆快照(heap)转储到 Android HPROF 文件中 。
HPROF 文件:文件里面存的数据是类 、类的实例 、实例的引用树 ,以此用来帮助查看内存的使用情况 。
Snapshot :获取 Java 堆内存详细信息 。
app heap 、default heap :分别是自己的应用在内存中分配的主堆和系统未指定堆时 。
下图是使用 AS 的 Profiler 功能所看到的。
可参考文章:
1.内存优化杂谈
2.极客时间专栏 Android 开发高手课