扫描件太大怎么缩小到1m以下,扫描件扫出来太大怎么改小

首页 > 经验 > 作者:YD1662022-10-26 12:33:48

本文作者:冯瑞;廖斌斌;刘丰恺

前言

应用安装包的体积会显著影响应用的下载速度和安装速度,按照 Google 的经验数据,包体积每增加 1M 会造成 0.17%的新增折损。抖音的一些实验也证明了包体积会显著影响下载激活的转化率。

Android 的安装包是 APK 格式的,在抖音的安装包中 DEX 的体积占比达到了 40%以上,所以针对 DEX 的体积优化是一种行之有效的包体积优化手段。

DEX 本质上是由 java/kotlin 代码编译而成的字节码,因此,针对字节码进行业务无感的通用优化成为我们的一个探索方向。

优化结果

终端基础技术团队和抖音基础技术团队在过去的一年里,利用 ReDex 在抖音包体积优化方面取得了一些明显的收益,这些优化也被同步到了其他各大 App 上。

在抖音、头条和其他应用上,我们的优化对 APK 体积的缩减普遍达到了 4%以上,对 DEX 体积的缩减则可以达到 8% ~ 10%

优化思路

在 android 应用的构建过程中,Java/Kotlin 代码会先被编译成 Class 字节码,在这个阶段 gradle 提供了 Transformer 可以进行字节码的自定义处理,很多插件都是在这个阶段处理字节码的。然后,Class 文件经过 dexBuilder/mergeDex 等任务的处理会生成 DEX 文件,并最终被打进安装包中。整个过程如下所示:

扫描件太大怎么缩小到1m以下,扫描件扫出来太大怎么改小(1)

所以,针对字节码的优化是有 2 个时机可以进行的:

  1. 在 transformer 阶段对 Class 字节码进行优化
  2. 在 DEX 阶段对 DEX 文件进行优化

显然,对 DEX 进行优化是更理想的一种方式,因为在 DEX 文件中,除了字节码指令外,还存在跨 DEX 引用、字符串池这样的结构,针对这些 DEX 格式的优化是无法在 transformer 阶段进行的。

在确定了针对 DEX 文件进行优化的思路后,我们选择了 facebook 的开源框架 ReDex 作为优化工具,并对其进行了定制开发。

选择 ReDex 的原因是它提供了丰富的基础能力,ReDex 的基础能力包括:

  1. 读写及解析 DEX 的能力,同时可以在一定程度上读取并解析 xml 和 so 文件
  2. 解析简单的 Proguard keep 规则并匹配类/方法/成员变量的能力
  3. 对字节码进行数据流分析的能力,提供了常用的数据流分析算法
  4. 对字节码进行合法性校验的能力,包括寄存器检查、类型检查等
  5. 一系列的字节码优化项,每项优化称为一个 pass,多个 pass 组成 pipeline 对 DEX 进行优化

扫描件太大怎么缩小到1m以下,扫描件扫出来太大怎么改小(2)

我们基于这些能力进行了定制和扩展,并期望最终建立完善的优化体系。

优化项

在抖音落地的优化项,包括 facebook 开源的优化和我们自研的优化,从其出发点来看,可以大致分为下面几种:

这几种优化没有明确的标准和界线,有时一个 Pass 会涉及到多种,下面详细介绍一下各项优化。

通用字节码优化ConstantPropagationPass

该 Pass 实际上包含了常量折叠和常量传播。

常量折叠是在编译期简化常量的过程,比如

1 y = 7 - 14 / 2 2 ---> 3 y = 0

常量传播是在编译期替代指令中已知常量的过程,比如

1 int x = 14; 2 int y = 7 - x / 2; 3 return y * (28 / x 2); 4 ---> 5 int x = 14; 6 int y = 7 - 14 / 2; 7 return (7 - 14 / 2) * (28 / 14 2);

上面的例子经过 常量折叠 常量传播优化后就会简化为

1 int x = 14; 2 int y = 0; 3 return 0;

再经过死代码删除就可以最终变为return 0。

具体的优化过程是:

  1. 对方法进行数据流分析,主要针对 const/move 等指令,得出一个寄存器在某个位置可能的取值
  2. 根据分析的结果,进行指令替换或指令删除,包括:

一个方法经过 ConstantPropagationPass 优化后,可能会产生一些死代码,比如例子中的int y = 0,这也为后续的死代码删除创造了条件。

AnnoKillPass

该 Pass 是用来移除无用注解的。注解主要分为三种类型:

除此之外,实际上为了支持某些系统特性,编译器会自动生成系统注解,虽然注解本身是 RUNTIME 类型,但是可见性是VISIBILITY_SYSTEM

举例说明

扫描件太大怎么缩小到1m以下,扫描件扫出来太大怎么改小(3)

编译器生成 1MainApplication$1这个匿名内部类,带有 EnclosingMethod 和 InnerClass 注解

扫描件太大怎么缩小到1m以下,扫描件扫出来太大怎么改小(4)

首页 123下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.