Android D8 编译器 和 R8 工具

1. D8、R8 发展历程

Android Studio 版本Android Gradle Plugin 版本变更
3.13.0.1引入 D8
3.23.2.0引入 R8、D8 脱糖默认开启
3.43.4.0默认开启 R8
1.1 D8 编译器

GoogleAndroid Studio 3.1 版本中引入 D8 编译器作为默认的 DEX 字节码文件编译器。通过在 gradle.properties 中新增 android.enableD8=true 开启 D8 编译器。

D8 编译器特点是:

  • 编译更快、时间更短;
  • DEX 编译时占用内容更小;
  • .dex 文件大小更小;
  • D8 编译的 .dex 文件拥有相同或者是更好的运行时性能;

根据 Google Android 团队使用 DexD8 编译器的测试对比数据:

d8 time.png

d8 size.png

1.2 R8 工具

GoogleAndroid Studio 3.2 中引入 R8 作为 ProGuard 的替代工具,用于代码的压缩(shrinking)和混淆(obfuscation)。通过在 gradle.properties 中新增 android.enableR8 = true 开启 R8 工具。

Disables R8 for Android Library modules only.

android.enableR8.libraries = false

Disables R8 for all modules.

android.enableR8 = false

1.3 Android Studio 3.4 版本 D8 R8 变更

Android Studio 3.4 版本中,R8desugaringshrinkingobfuscatingoptimizingdexing 都合并到一步进行执行。在 Android Studio 3.4 以前的版本编译流程如下:

compile_with_d8_proguard.png

合并之后编译流程如下:

compile_with_r8.png

注意,如果我们在 build.gradle 中配置了 useProguard = false 则不管是否开启 R8 编译都会使用 R8 进行压缩代码。

2. 脱糖

Android Studio 为使用部分 Java 8 语言功能及利用这些功能的第三方库提供内置支持。默认工具链对 javac 编译器的输出执行字节码转换(称为 desugar),从而实现新语言功能。

脱糖即在编译阶段将在语法层面一些底层字节码不支持的特性转换为基础的字节码结构,(比如 List 上的泛型脱糖后在字节码层面实际为 Object); Android 工具链对 Java8 语法特性脱糖的过程可谓丰富多彩,当然他们的最终目的是一致的:使新的语法可以在所有的设备上运行。

经过上面 D8R8 的了解,D8 已经支持脱糖,让 Java 8 提供的特性(如 lambdas)可以转换成 Java 7 特性。把脱糖步骤集成进 D8 影响了所有读或写 .class 字节码的开发工具,因为它会使用 Java 8 格式。可以在 gradle.properties 中禁用脱糖。

android.enableIncrementalDesugaring=false.
android.enableDesugar=false

2.1 Lambda 表达式

Java 8 中一个重大变更是引入 Lambda 表达式。

public class Lambda {
public static void main(String[] args) {
logDebug(msg-> System.out.println(msg), “HelloWorld”);
}

static void logDebug(Logger logger, String msg) {
logger.log(msg);
}

@FunctionalInterface
interface Logger {
void log(String msg);
}
}

通过 javac 指令将上面的 Lambda.java 转换为字节码。

$javac Lambda.java

接下来通过 javap -v 指令查看字节码的详细内容:

dengshiweideMacBook-Pro:Desktop dengshiwei$ javap -v Lambda.class
Classfile /Users/dengshiwei/Desktop/Lambda.class
Last modified 2019-5-12; size 1120 bytes
MD5 checksum 67301305720e60d4ef1ff286769768e6
Compiled from “Lambda.java”
public class Lambda
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #9.#25 // java/lang/Object.“”😦)V
#2 = InvokeDynamic #0:#30 // #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 9: Logger; #̲3 = String …Logger;Ljava/lang/String;)V
#5 = InterfaceMethodref #10.#33 // LambdaKaTeX parse error: Expected 'EOF', got '#' at position 34: …lang/String;)V #̲6 = Fieldref …Logger
#11 = Utf8 Logger
#12 = Utf8 InnerClasses
#13 = Utf8
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 main
#18 = Utf8 ([Ljava/lang/String;)V
#19 = Utf8 logDebug
#20 = Utf8 (LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲21 = Utf8 …mainKaTeX parse error: Expected 'EOF', got '#' at position 3: 0 #̲22 = Utf8 …Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#28 = MethodType #22 // (Ljava/lang/String;)V
#29 = MethodHandle #6:#42 // invokestatic Lambda.lambda$mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲30 = NameAndTyp…Logger;
#31 = Utf8 HelloWorld
#32 = NameAndType #19:#20 // logDebug:(LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 29: …lang/String;)V #̲33 = NameAndTyp…Logger
#41 = Methodref #50.#51 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲42 = Methodref …mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲43 = Utf8 …Logger;
#45 = Utf8 java/lang/System
#46 = Utf8 out
#47 = Utf8 Ljava/io/PrintStream;
#48 = Utf8 java/io/PrintStream
#49 = Utf8 println
#50 = Class #53 // java/lang/invoke/LambdaMetafactory
#51 = NameAndType #54:#57 // metafactory:(Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲52 = NameAndTyp…mainKaTeX parse error: Expected 'EOF', got '#' at position 25: …lang/String;)V #̲53 = Utf8 …Lookup
#56 = Utf8 Lookup
#57 = Utf8 (Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 173: …voke/CallSite; #̲58 = Class …Lookup
#60 = Utf8 java/lang/invoke/MethodHandles
{
public Lambda();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.“”😦)V
4: return
LineNumberTable:
line 1: 0

public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: invokedynamic #2, 0 // InvokeDynamic #0:log:()LLambdaKaTeX parse error: Expected 'EOF', got '#' at position 26: … ldc #̲3 …Logger;Ljava/lang/String;)V
10: return
LineNumberTable:
line 3: 0
line 4: 10

static void logDebug(Lambda L o g g e r , j a v a . l a n g . S t r i n g ) ; d e s c r i p t o r : ( L L a m b d a Logger, java.lang.String); descriptor: (LLambda Logger,java.lang.String);descriptor:(LLambdaLogger;Ljava/lang/String;)V
flags: ACC_STATIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokeinterface #5, 2 // InterfaceMethod Lambda$Logger.log:(Ljava/lang/String;)V
7: return
LineNumberTable:

最后

这里我希望可以帮助到大家提升进阶。

内容包含:Android学习PDF+架构视频+面试文档+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~

img
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
QtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8yMjQzNjc0MC01OTA0Mjg2Yjk1ZjRkYmEw?x-oss-process=image/format,png)
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值