Facebook APP优化工具ReDex
https://github.com/facebook/redex
Redex是专门的用于Android字节码的优化,在apk大小、运行速度上都有优化。
Redex基于管道的方式来优化Android的 .dex文件,一个源.dex文件通过管道进行一系列的自定义转换后,将得到一个优化的.dex文件。
Redex优化的时机
Redex选择基于字节码文件而不是java源码进行的优化,即在.dex后进行优化。
这样的优化更为全面,且某些优化只能在dex中进行。
管道的概念
Redex的优化是链式的,方便的对优化进行裁剪。
Redex默认的管道功能支持(在config/default.config):
{
"redex" : {
"passes" : [
"ReBindRefsPass",
"BridgePass",
"SynthPass",
"FinalInlinePass",
"DelSuperPass",
"SingleImplPass",
"SimpleInlinePass",
"StaticReloPass",
"RemoveEmptyClassesPass",
"ShortenSrcStringsPass"
]
}
}
Redex做了哪些优化
进一步混淆和压缩
对字节码做类似于java层的proguard混淆操作。
使用内联函数
内联函数是在编译期间将函数体直接嵌入该函数的调用处,也就是在编译时不具备函数的性质,不存在执行函数调用产生的开销,从而得到提高代码运行性能的目的,同时,如果正确的应用它,还可以减小编译后生成的文件大小。
最简单的一个例子是适配器类型的函数,这些函数通常是用来封装一些小函数,以提供更简洁统一的 API 接口,或者是由于参数列表不同而存在的多个重载函数,亦或者是setter/getter 函数等,这些函数在最终生成的 APK 中有的可能根本不会被调用到。因此在 .dex 文件阶段对这些函数进行内联操作,是很大的一个优化点。
无用代码的消除
无用代码的移除类似于标记清除(mark-sweep)垃圾回收算法。我们从某个明确会调用的入口,例如 MainActivity 开始遍历各个条件分支和函数调用,在生成的图中标记访问到的代码,在遍历了所有的条件分支和函数调用之后,就可以判定那些没有被标记的函数是无用的代码,可以安全的删除。
对于只有一个实现类的接口或父类,直接用实现类代替
基于反馈(启动加载顺序测试)的 Class 字节码布局
类字节码在单个 Dex 中的布局是根据编译顺序而不是运行时行为决定,即便 Multidex 会将 App 定义的组件以及部分启动需要的类放在 Main Dex 中,但依然不是根据运行时顺序布局,这会导致程序启动时需要查找随机分布在 Dex 中的类。
ReDex 会将 APK 在 Lab 中试运行,并跟踪启动时哪些类需要加载,然后将这些类字节码放到 Dex 前部,减少启动时从闪存中寻找类的时间,从而提高 App 启动速度。