本文的作者:冯·鲁伊;狮子宾犬;刘广海
应用程序包的音量将显着影响应用程序的下载速度和安装速度。根据Google的经验数据,包装量将对每次增加1m的新损害造成0.1.的新损害的0.17%。DOUYIN的某些实验还证明,包装的数量将显着影响下载激活的转换率。
Android的安装程序包为APK格式。Douyin安装软件包中的DEX量已达到40%以上。因此,DEX的体积优化是一种有效的软件包量优化方法。
DEX本质上是由Java/Kotlin代码编译的字节码。因此,对字节代码的无业务业务的普遍优化已成为我们探索的方向。
在过去的一年中,码头基本技术团队和Douyin基本技术团队为Douyin袋的数量优化带来了一些明显的好处。这些优化也已与其他主要应用程序同步。
在Douyin,头条新闻和其他应用中,我们的APK体积的优化通常达到4%以上,DEX量的减少可以达到8%?10%
在构建Android应用程序期间,Java/Kotlin代码将首先编译为类字节码。在此阶段,Gradle提供了变形金程序来自定义字节码。:
因此,字节码的优化可用于两个机会:
显然,DEX的优化是一种更理想的方法,因为在DEX文件中,除了字节码指令外,还有诸如交叉滴定引用和字符串池之类的结构。这些DEX格式的优化不能在Transferterperiod中的变压器中。
确认了DEX文件的优化后,我们选择了Facebook的开源框架Redex作为优化工具并对其进行了自定义。
选择REDEX的原因是它提供了丰富的基本功能。REDEX的基本能力包括:
我们已经定制并扩展了这些功能,我们希望最终建立最终的优化系统。
Douyin着陆的优化项目,包括对Facebook开源的优化以及我们自我开发的自我研究的优化。从其起点的角度来看,它可以大致分为以下内容:
这些类型没有明确的标准和边界。有时,一通道涉及各种各样。以下是每个优化的详细介绍。
ConstantPropagationPass此通行证实际上包含恒定的折叠和恒定通信。
恒定折叠是在编译期间简化常数的过程,例如
恒定通信是在汇编期间替换说明中的已知恒定数量的过程,例如
以上示例将简化为
删除死亡代码后,您最终可以成为。
特定的优化过程是:
在通过ConstantPropagationPass优化方法后,可以生成一些死亡代码,例如该示例,这也为后续的死亡代码删除创造了条件。
Annokillpass用于删除无用的注释。注释主要分为三种:
此外,实际上,为了支持某些系统特征,编译器将自动生成系统注释。尽管注释本身是运行时类型,但可见性质是
例如
编译器生成带有封闭信息和InnerClass注释的匿名内部类
该系统提供以下接口以获取与类相关的信息,这是通过分析相关系统注释来实现的
如果没有代码中使用这些接口的逻辑,则可以安全地删除注释的这一部分以实现缩小包装大小的目的。
RenameClassspass此通过通过减少类名称的字符串长度来减少包装的音量
例如,如果将类名称更改为类名称字符串的长度,以实现包装大小的目的。实际上,Proguard本身提供了相似的功能:,效果如下:
但是该处理将影响Redex Interdexpass的算法逻辑(交际可以参考以下内容),从而导致收入减少收入
基本原因是,在更名后,它会影响互互发函数参考的重新分布,从而导致Interdex收入
体重方法的优化相对复杂,并且存在许多不规则性,例如与其他优化的潜在冲突,因此我们采用了第二个解决方案。
需要解决的一个关键点是如何确定是否可以安全地重命名班级名称。我们采用了一种更聪明的方式。redex将分析产品上传递的映射文件。相同的处理策略不会引起一系列问题,例如反射/本机呼叫/序列化。
但是,它仍然遇到了各种奇怪的问题,例如签名系统注释的到期问题。签名注释的内容是一种非标准类别名称格式,因此在重新命名后,只需反映字符串或更新字符串或更新类型类型将导致签名注释失败。最后,通过对签名格式进行深入分析,可以避免此问题。
StringBuilderOutlineerPass此通行证已优化,用于分析和缩小StringBuilder的呼叫。使用死亡代码删除,它可能具有良好的优化效果。
为什么优化?在Java的代码开发期间,字符串操作几乎是我们要做的最常见的事情,无论是实际的处理字符串缝线还是不同数据类型之间的缝合操作。这些缝线操作将由Java优化到StringBuilder。优化:
因此,我们分析了StringBuilder的所有呼叫。在最好的情况下,可以将多种方法优化为调用。此方法是一种大纲方法。特定的参数缝线和to缝被隐藏在功能中:
优化步骤可以简单地分为以下步骤:
InterDexpass是跨核引用的优化。
Cross Dex引用是指DEX需要在另一个DEX中“使用”类/方法/变量时,您需要在此DEX中保存相应的类/方法/变量ID。字符串,然后需要定义此字符串因此,更改类别/方法/变量的分布和DEX中的字符串都可以减少参考的数量,从而减少DEX的体积。从以下原理中可以看到优化无效的优化是无效的单个dex。
从上图可以看出,在类重新编排后,DEX0的参考文献和方法参考的数量减少,并且DEX的体积将减少。
特定的优化过程是:
rebindRefspass是方法的优化,其原理与互二比相同。
在字节码中,该指令需要方法参考。在许多情况下,此参考指向子类或实现类参考。替换此引用到父类和接口的方法不会影响运行时逻辑。同时,IT将减少DEX引用的中国方法的数量。当生成DEX时,该方法引用的65536限制通常是遇到的第一批瓶颈,并且这种优化也可以减轻这种情况。
如上图所示,优化之前的调用方法的调用指令是子类引用。伪建筑如下所示,需要使用2个参考。
优化后,调用说明指向其父亲级应用程序。可以将两个参考合并为一个,从而减少了DEX中的数量
Kotlindataclasspass是Kotlin数据类的优化。基本思想是简化数据类的生成代码。
Kotlin中有一个可靠的语句,可以更方便地创建多个变量。基本用法如下
Kotlinc将为类生成GET方法和组件方法,如下所示是伪代码表示
可以看出,get和组件的逻辑是相同的,因此在编译期间,您可以匹配全局匹配。使用get替换组件,然后删除组件。
Kotlin编译器具有由数据类生成的类似代码结构,因此它可以生成辅助方法,然后在所有数据类ToString方法中调用此辅助方法,即减少说明数的外部董事数量。
平等和哈希码也可以优化,但风险相对较高。因此,单独为这些优化配置了开关,并且根据情况,业务团队可以打开情况。
RegaloCpassdex和其他文件被压缩以制作APK。如果可以通过更改DEX的含量来提高压缩率,则最终包装量也将减少。RegaloCpass是通过重新分配存款人来提高压缩率。
当DX生成DEX时,它使用线性寄存器分配算法。基本步骤是执行幸存的变量分析,然后计算每个变量的活动范围,然后根据活动间隔为变量分配寄存器。优势是它运行迅速,但结果通常不是最佳的。
例如,以下代码,DX分配6个寄存器,V0?V5
相反,Redex使用颜色算法进行寄存器分配。基本步骤是执行幸存的变量分析并构建冲突图。冲突图的每个节点都是变量。如果两个变量可以同时生存,则在两个节点同时在两个节点处。建立末端之间的边缘,最终的颜色映射是彩色的。每种颜色代表寄存器。颜色方法相对较慢,结果通常更好。对于上面的相同代码,颜色方法使用4个寄存器V0?V3。
DEX中该方法中使用的寄存器越少,内容重复率越高,压缩率越大,减少了包装的体积。
Douyin是具有最大,最复杂的操作环境的应用之一。在Redex的早期,由于复杂性估计不足,这是由独立的灰色和全灰色引起的一些问题。在解决问题的过程中,我们逐渐形成了一组迭代过程,以确保优化的稳定性。这里是我们遇到的典型问题和当前的迭代过程。
一般而言,兼容性问题,只要优化字节代码规范,就不会出现兼容性问题,因为Dalvik/Art还按照规格检查并运行字节代码。问题也应该是一个常见的问题。许多事情的例外,Redex在品牌手机的某些Android 5.x型号上遇到了问题。
从日志和某些钩子的角度来看,某些品牌的手机已经对5.x艺术进行了许多魔法改革,这可以推断出其魔术改革存在一些问题,这在验证和验证方面也可能存在问题正确字节码的操作。一个可能的原因是,当优化Redex时,将重新安排某些方法的指令的顺序。此重新划线不会影响该方法的逻辑,但可能会更改某些说明。当您测试这种方法时,您可以报告验证错误以引起崩溃。
最后,这些方法的优化通过黑名单配置跳跃。在随后的优化过程中,没有遇到类似的问题。
复杂方案的优化很复杂,并且代码具有多种代码。它为静态分析和优化增加了一些困难,并且更有可能遇到问题。以下是两个典型问题:
在初始化代码中调用,这是一个空的方法。调用它的目的是触发类加载以执行句子块。如果删除了此空方法,则将导致初始化不可用。在随后的过程中,指针将被清空。
对于简单的反射用法,例如类(...),可以分析静态分析,但是对于某些字符串缝线或嵌套反射,很难分析静态分析。因此,有必要非常谨慎以优化优化可以反映的代码。一般而言,不会通过反思来调用匿名内部类。基于前提,我们进行了匿名的内部类重命名优化,但是在Grayscaleit发现某些第三部分SDK将通过复杂的运行时逻辑反映匿名内部类,最终导致ClassNotFoundError。
复杂方案的优化是由不规则的业务代码引起的,但更多是由优化先决条件引起的(空方法可以删除/匿名内部类不会反映)。因此,优化验证。
为了减少稳定性问题,我们总结了Redex通过的迭代过程。
在对通行证有初步的想法之后,该小组将进行可行性讨论。如果从理论上讲,它可以输入开发和验证阶段,然后同时执行至少两轮独立的灰度验证和商业团体通行证评论。Gray验证。如果在任何链接中都找到任何链接,则整个过程都将重新处理。。
通过这个过程,我们将稳定问题的可能性大大减少到了灰色阶段。在不断改善迭代过程的同时,我们还通过加强单元测试和自动化测试来探索质量。
Redex仍在迭代。将来,我们将继续在以下方向上进行探索:
客户基础设施团队是一支由大型前端基本技术组成的全球研发团队(在北京,上海,杭州,杭州,深圳,广州,新加坡,新加坡和美国拥有研发团队。提高公司整个产品线的性能,稳定性和工程效率的基础架构;所支持的产品包括但不限于Douyin,当今的头条新闻,西瓜视频,飞行书籍,瓜瓜龙等,桌面和其他终端都具有 -深度研究。
现在是!客户端 /前端 /服务器 / END Intellignent算法 /测试开发已在全球范围内招募!让我们使用技术一起改变世界。如果您有兴趣,请联系fengrui.0@bytedance.com,电子邮件主题简历 - 名称搜索意图指望City-Telephone。
Douyin Android基础技术团队是对最终团队的深刻追求。我们专注于绩效,建筑,袋子大小,稳定性,基本图书馆,汇编和构造等的深层培养。欢迎有愿望的人与我们共同构建1亿个用户应用程序!
您可以输入“ Douyin Basic Technology Android”的相关立场,或联系电子邮件:Xiaolin.gan@bytedance.com,直接在-in -in -law中发送简历或咨询相关信息!
原始:https://juejin.cn/post/710422863759477965