抖音 Android 性能优化系列:Java 内存优化篇( 四 )

  • 系统大对象:系统大对象如 PreloadDrawable、JarFile 我们通过源码分析确定主动释放并不干扰原有逻辑,在启动完成或在内存触顶时主动反射释放 。
  • 动画:用原生动画代替了内存占用较大的帧动画,并对 Lottie 动画泄漏做了手动释放 。

抖音 Android 性能优化系列:Java 内存优化篇

文章插图
 
图 14. 大对象优化点
小对象小对象优化我们集中在字段优化、业务优化、缓存优化三个纬度,不同的纬度有不同的优化策略 。
抖音 Android 性能优化系列:Java 内存优化篇

文章插图
 
图 15. 小对象优化思路
通用类优化在抖音的业务中,视频是最核心且通用的 Model,抖音业务层的数据存储分散在各个业务维护了各自视频的 Model,Model 本身由于聚合了各个业务需要的属性很多导致单个实例内存占用就不低,随着用户使用过程实例增长内存占用越来越大 。对 Model 本身我们可以从属性优化和拆分这两种思路来优化 。
  • 字段优化:针对一次性的属性字段,在使用完之后及时清理掉缓存,比如在视频 Model 内部存在一个 Json 对象,在反序列完成之后 Json 对象就没有使用价值了,可以及时清理 。
  • 类拆分:针对通用 Model 冗杂过多的业务属性,尝试对 Model 本身进行治理,将各个业务线需要用到的属性进行梳理,将 Model 拆分成多个业务 Model 和一个通用 Model,采用组合的方式让各个业务线最小化依赖自己的业务 Model,减少大杂烩 Model 不必要的内存浪费 。
业务优化
  • 按需加载:抖音这边 IM 会全局保存会话,App 启动时会一次性 Load 所有会话,当用户的会话过多时相应全局占用的内存就会较大,为了解决该问题,会话列表分两次加载,首次只加载一定数量到内存,需要时再加载全部 。
  • 内存缓存限制或清理:首页推荐列表的每一次 Loadmore 操作,都不会清理之前缓存起来的视频对象,导致用户长时间停留在推荐 Feed 时,缓存起来的视频对象过多会导致内存方面的压力 。在通过实验验证不会对业务产生负面影响情况下对首页的缓存进行了一定数量的限制来减小内存压力 。
缓存优化上面提到的视频 Model,抖音最早使用 Manager 来管理通用的视频实例 。Manager 使用 HashMap 存储了所有的视频对象,最初的方案里面没有对内存大小进行限制且没有清除逻辑,随着使用时间的增加而不断膨胀,最终出现 OOM 异常 。为了解决视频 Model 无限膨胀的问题设计了一套缓存框架主要流程如下:
抖音 Android 性能优化系列:Java 内存优化篇

文章插图
 
图 16. 视频缓存框架
 
使用 LRU 缓存机制来缓存视频对象 。在内存中缓存最近使用的 100 个视频对象,当视频对象从内存缓存中移除时,将其缓存至磁盘中 。在获取视频对象时,首先从内存中获取,若内存中没有缓存该对象,则从磁盘缓存中获取 。在退出 App 时,清除 Manager 的磁盘缓存,避免磁盘空间占用不断增长 。
图片关于图片优化,我们主要从图片库的管理和图片本身优化两个方面思考 。同时对不合理的图片使用也做了兜底和监控 。
图片库针对应用内图片的使用状况对图片库设置了合理的缓存,同时在应用 or 系统内存吃紧的情况下主动释放图片缓存 。
图片自身优化我们知道图片内存大小公式 = 图片分辨率 * 每个像素点的大小 。
图片分辨率我们通过设置合理的采样来减少不必要的像素浪费 。
//开启采样ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)    .setDownsampleEnabled(true)    .build();Fresco.initialize(context, config);//请求图片时,传入resize的大小,一般直接取View的宽高ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)    .setResizeOptions(new ResizeOptions(50, 50))    .build();mSimpleDraweeView.setController(    Fresco.newDraweeControllerBuilder()        .setOldController(mSimpleDraweeView.getController())        .setImageRequest(request)        .build());而单个像素大小,我们通过替换系统 drawable 默认色彩通道,将部分没有透明通道的图片格式由 ARGB_8888 替换为 RGB565,在图片质量上的损失几乎肉眼不可见,而在内存上可以直接节省一半 。


推荐阅读