R8 如何优化我们的代码(1) -- 减少类的加载

为什么写这个系列

主要是看了 芦大和 P 大的文章,受益颇多,虽然有很多不解的地方,但是大体上已经有了学习的脉络,刚好看到很多人都觉得这几篇文章读起来很吃力,其实我也一样。 要搞懂大佬们的文章,主要是要对 r8 和 art 有一定理解, art 实验起来颇为不易,我们暂且跳过(后面我慢慢补,其实现在我也没太懂,等我学一下再说)

r8对于大部分 app 开发者而言,看起来应该不会有太多阻碍,所以先开坑 r8吧

r8相关部分主要参考jakewharton的 blog

因为 r8 的版本不同,所以部分结果可能和 jw 的原文有出入,大家自行分辨即可

准备工作

准备好独立的 r8 编译环境 具体可以参考官方文档谷歌 r8

不过大部分人肯定会报错, 在构建 r8 之前,我们需要下载一个特殊的工具

bash 复制代码
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

然后加入到环境变量中

bash 复制代码
export PATH="$PATH:$HOME/depot_tools"

最后按照 google 文档 就可以了

shell 复制代码
$ git clone https://r8.googlesource.com/r8
$ cd r8
$ tools/gradle.py r8

一阵漫长的等待

这个 r8.jar 就是我们的目标产物了,

整个仓库最终大概最终有个 20gb 左右,首次编译我差不多 2 小时才好

不过这里有一个疑问,我在 maven 上直接下载的 r8.jar 是无法独立运行的,不知道和这个构建出来的 r8.jar 具体有啥区别, 有知道的大佬可以指教下

这条路打通以后, 对我们研究 r8 是很有好处的,毕竟可以自己 build 出r8 不用等 agp 升级了。

准备 2 个命令 把 java 和 kotlin 的代码打成 jar 包,方便我们用 jadx 反编译直接看

shell 复制代码
# 指定哪个类是 main 方法的类
jar cvfe main.jar org.example.main *
shell 复制代码
# 指定哪个类是 main 方法的类
kotlinc src/main/kotlin/Main.kt -d main.jar

静态化优化

看下代码:

kotlin 复制代码
package org.example

class Greeter(val greeting:String){
    fun greet(name: String) = "$greeting,$name"
    companion object{
        fun hello() = Greeter("hello")
        fun random() = Greeter("${Math.random()}")
    }
}

fun main() {
    println(Greeter.hello().greet("world"))
    println(Greeter.random().greet("world"))

}

混淆文件

arduino 复制代码
-keepclasseswithmembers class * {
  public static void main(java.lang.String[]);
}
-dontwarn org.jetbrains.annotations.NotNull
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
    <fields>;
}
-keepclassmembers class kotlin.Metadata {
    public <methods>;
}
-dontobfuscate

我们用 kotlinc build 出一个 jar 包

然后放到 jadx 中反编译一下

看下具体的指令:

如果看不懂的话也没关系,我们可以看下代码

其实是符合预期的对吧,

用 r8 处理一下

shell 复制代码
java -cp r8.jar com.android.tools.r8.R8 --release --classfile --output ouput.jar --pg-conf /Users/xxx/Desktop/company_code/R8Test/rules.txt  --lib  /Users/xxx/Library/Android/sdk/platforms/android-33/android.jar /Users/xxx/Desktop/company_code/R8Test/main.jar

然后再用 jadx 反编译一下

还是先看指令

再看代码

经过 r8 处理过的代码,其 伴生类 被抹除,等于少了一个类的加载

如果我们把代码改的简单点,其优化效果会更加明显

kotlin 复制代码
package org.example

class Greeter(val greeting:String){
    fun greet(name: String) = "$greeting,$name"
    companion object{
        fun hello() = Greeter("hello")
        fun random() = Greeter("${Math.random()}")
    }
}

fun main() {
    println(Greeter.hello().greet("world"))
}

这次直接啥都不要了 直接输出对应的字符串

实际上不止是伴生对象,object 单例 也是有类似的优化

修改下我们的代码

kotlin 复制代码
package org.example

class Greeter(val greeting:String){
    fun greet(name: String) = "$greeting,$name"
    companion object{
        fun hello() = Greeter("hello")
        fun random() = Greeter("${Math.random()}")
    }
}

object HelloGreeter{
    fun hello() = Greeter("hello")
}

fun main() {
    println(HelloGreeter.hello())

}

未使用 R8 的时候

还需要取 HelloGreeter 的实例

使用 r8 的时候

优化效果惊人:

这种优化 不仅仅是针对 kotlin,java 也是一样

有兴趣的可以自行做下实验

java 复制代码
package org.example;

public class Thing {
    public static final Thing INSTANCE = new Thing();

    private Thing() {}

    public void doThing() {
        if (Math.random() > 0.5) {
            System.out.println(">0.5");
        }

    }
}

总结一下,R8 的代码优化工作 会帮助我们减少类的加载

相关推荐
90后的晨仔13 分钟前
Android Studio 项目模板完全指南
android
summerkissyou198716 分钟前
Android-SurfaceView-投屏-常见问题
android·surfaceview
明天就是Friday26 分钟前
Android实战项目④ OkHttp WebSocket开发即时通讯App 完整源码详解
android·websocket·okhttp
吉哥机顶盒刷机1 小时前
好物分享:DNA-Android-4.0.5安卓固件解包、打包工具
android·好物分享
三棱球1 小时前
App逆向学习笔记(三)——Android开发入门课
android·笔记
安卓机器2 小时前
rom定制系列------魅族16x 解锁bl root与Flyme9安卓10线刷固件 传感器修复
android·魅族16x玩机
wellc4 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
CYY955 小时前
Android 打印 SO 库的异常日志
android
找藉口是失败者的习惯6 小时前
深入理解 Android 无障碍服务
android