近期贝壳找房安卓app在测试时发现报了OOM异常(即内存溢出),主要原因是图片占用内存空间过大。
操作步骤:打开贝壳找房,设置城市为“徐州”, 然后点击“二手房”图标进入“二手房列表页”, 向上滑动列表。
使用 Picasso
使用 Glide
上图是 Android Profiler 抓取的运行时内存, 使用 Picasso 时 Java 堆占用了 220.7M 字节, 使用 Glide 时 Java 堆占用了 85.8M。 直观上内存使用减少了一半。
Android8.0 及后续版本将 Bitmap 缓存在 Native 层, 理论上不会因为缓存图片导致 OOM; 而贝壳找房安卓 app 用户 Android8.0 以下占比 64%左右, 优化图片内存管理对这部分用户有意义。
改造成本
因为 Glide 比 Picasso 多了一个 Context 参数, 所有原来调用 Picasso 方法的地方都要修改。
使用 Glide
二手房业务都使用 LJImageLoader.java 显示图片, 只需要扩展方法加个 Context 参数, 调用时多传入一个 context 即可。
原理
Glide 在内存上使用二级缓存, 即当前正在使用的 activeResources(其实就是个 map,保存了图片的弱引用)和 LruCache(界面未显示的图片)。 在测试机魅族上 LruCache 默认只有 16M 字节, 而 Picasso 的 LruCache 在 160M 左右。
列表向上滑动时观察内存基本不变, 这是因为 Glide 及时回收了内存。
滑动 listview/recyclerview
复用 item 使用相同 ImageView 显示图片时会先释放其在 Glide 中的资源
因为 ListView 复用了 view,在数据不变情况下,内存中 ListView 缓存的 itemView 个数是固定的, 从而 Glide 的 activeResources 缓存的个数也是固定的。 前提:ListView 数据个数很多且要向上滑动一下。
对于 ListView 滑动时 activeResources 数量是不变的
在滑动列表时,将移出屏幕 item 的图片从 activeResources 中移除,并添加到 LruCache 中, 如果 LruCache 达到上限则自动清理。
Glide 比 Picasso 的 2 个优势:
1、因为 Glide 支持 Activity/Fragment 的生命周期, Glide 在生命周期 onStart 函数里注册连接状态变化广播并继续处理当前界面图片任务; 在生命周期 onStop 函数里取消注册连接状态广播并暂停处理当前界面图片任务; 在生命周期 onDestroy 函数里将当前界面使用的 activeResources 里的资源移出并添加到 LruCache 中。
2、当前 Activity A 有很多个图片, 这时再启动 Activity B、C、D, 虚拟机可能会 gc 隐藏的 activity,从而释放当前 app 的内存。
展望
安卓主流图片三方框架 Glide、Picasso、Fresco 各有特点, 而 Glide 是谷歌推荐的图片库。 贝壳找房 app 安卓端用 Glide 替换 Picasso 的成本较小, 收益是 64%使用 android8.0 以下用户不再出现 OOM 问题。
作者介绍:
高瑞,贝壳找房 Android 工程师,目前负责贝壳找房 app 安卓端研发工作。
本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。
原文链接:
https://mp.weixin.qq.com/s/kOFRvRANG77qWmz3YSPIfw
评论