你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解

作者:恋猫de小郭日期:2026/2/20

本篇是来自 Android Developers 的播客 What’s so great about R8?》 的整合,核心是讨论了 Android R8 编译器以及它对性能的影响,参与讨论的嘉宾包括来自 Android 工具团队、R8 团队和平台性能团队的专家(Tor Norby, Romain Guy, Sean, Chris, Shai)。

这是一篇让你对 R8 不再误解的内容

D8 与 R8 编译器的区别

首先可能不少人还不理解 D8 与 R8 的区别,在 Android 开发里,我们都知道代码从 Java/Kotlin 编译为字节码后,还需要经过另一层编译才能在设备上运行:

  • D8 编译器 :这是开发者在日常开发中使用的调试编译器,它速度快、支持增量编译,目的是让开发者能够以最快的速度在设备或模拟器上编辑、运行和调试代码,但它不会对代码进行深度的性能优化
  • R8 编译器 :这是用于发布 (Release build) 的全局优化编译器,它会将整个应用作为一个整体进行静态分析,花费可能高达数十分钟的时间来应用各种复杂的优化,从而生成体积最小、运行最快的最终代码

所以,D8主要处理 dexing(将Java字节码转换为Dalvik字节码)和基本的代码缩小,而 R8 的功能更全面,包括高级优化如跨模块分析 。

R8 的核心优化机制

所以 R8 不仅仅是混淆代码,它在底层做了大量提升性能的工作:

  • Tree Shaking :正常应用里通常会引入大量第三方库,但往往只使用其中的一小部分功能,而 R8 能够通过全局静态分析,找出哪些代码在运行时永远不会被调用,并将其完全移除当然,这也是很多时候大家讨厌 R8 的原因,因为 R8 在高版本默认开启后,应用升级就崩溃
  • 方法与参数内联 :R8 会分析代码的调用情况,将总是接收相同参数的方法,或调用频繁但非常简短的方法直接内联到调用处,从而减少虚拟方法调用的开销
  • 合并接口:如果 R8 发现一个接口在实际生产代码中只有一个实现类(例如仅仅为了单元测试而提取的接口),它可以将该接口直接合并到实现类中,减少一层指针查找的性能损耗
  • 与 ART 运行时的协同优化:R8 的工作会为设备上的 ART (Android Runtime) 编译器“铺平道路”,结合 Baseline Profiles(基准配置文件),R8 知道哪些代码是启动时的“热代码”,并会在 DEX 文件中留下提示,帮助 ART 在用户设备上进一步生成高效的机器码
  • 移除 Kotlin 空安全检查:Kotlin 会在底层插入大量的非空检查 (如checkNotNullParameter 等),在发布版本中,R8 可以基于全局分析证明某些值永远不为空从而移除检查,或者将其替换为不带冗长字符串的精简指令,既减小了体积又提升了性能

所以可以看出来, R8 比 D8 做了更多的性能和优化工作,本质上其实就是为了让 App 更快更小。

所以了解 R8 做了什么也很重要,因为经过 R8 后你的 App 运行可能会出现某些奇怪问题,而找到这些问题的原因,就需要你清楚知道 R8 做了什么

R8 面临的最大挑战:反射与 Keep Rules

但是就像我们前面说的,R8 也带来了很多问题,比如它虽然 Tree Shaking ,但是它对于 Tree Shaking 也没办法做到尽善尽美:

  • 反射与 JNI 带来的问题 :由于 R8 是静态分析工具,它很难预测在运行时通过字符串动态调用的类、方法或字段(如反射),如果 R8 看不到某个类的静态调用,就会将其当作“死代码”移除,导致应用在运行时抛出 ClassNotFoundException 崩溃
  • 保留规则 (Keep Rules) :为了反射和 JNI 问题,开发者必须编写 Keep Rules 来明确告诉 R8 哪些类和方法不能被优化或移除,但是很多第三方库为了省事,会编写过于宽泛的规则(例如要求保留整个库的所有代码),这会严重阻碍 R8 发挥作用并拖累整体性能

恩, GSY 大体上就是这样,因为 GSY 播放器里有很多 JNI 和反射调用,所以在提供的 Keep Rules 里,都是直接用宽泛的规则,省事。

开发者体验与工具链的改进

另外,如今的 R8 开发体验和资料改进已经非常完善,比如大家一开始认识的 R8 已经是“女大十八变”了:

  • 反混淆与崩溃日志:R8 会将类名和方法名重命名为简短的字母(如 "a", "b", "c")以节省空间,为了让崩溃日志可读,R8 会输出 Mapping 文件,现在的 Android Studio 提供了不错的集成(Android Studio 的 App Quality Insights),开发者可以在 IDE 中直接点击按钮,自动下载和映射线上的崩溃堆栈,体验上和调试 D8 构建一样顺畅(它会利用线上的 mapping 文件对崩溃堆栈进行反混淆
  • 官方文档大翻新:在此之前,R8 的文档一言难尽,而现在 R8 团队对官方文档进行了大规模翻新,详细解释了 R8 的工作原理、Keep Rules 的语法规范、最佳实践以及如何排查不合理的保留规则

R8 会大量更改源码的情况,所以栈轨迹无法指向原始代码,例如行号以及类和方法的名称可能会发生变化,所以在使用 retrace 时,需要 mapping 文件,例如 : $ANDROID_HOME/cmdline-tools/latest/bin/retrace app/build/outputs/mapping/$releaseVariant/mapping.txt trace.txt

R8 的新特性与未来方向

而实际上 R8 目前还处于高速发展的阶段,未来还有需要多能力提供,例如:

  • 局部/包级别的 R8 优化 (Gradual R8) : 为了帮助历史包袱沉重的大型应用逐步迁移到 R8,R8 团队推出了按包范围开启 R8 的功能,开发者可以先对 AndroidX 库、Compose 等确定安全的包开启优化,然后逐步将自己的业务代码加入优化范围,从而降低崩溃风险
  • @UsesReflection 注解:相比于在单独的配置文件中写晦涩的 Keep Rules,R8 团队正在推广一种新的 @UsesReflection 注解,开发者可以直接在发起反射调用的地方添加注解,指明它反射了什么目标,这种方式让配置跟随代码移动,支持条件保留,且能被 IDE 直接识别和检查
  • 优化的资源缩减 (Optimized Resource Shrinking) :过去,代码缩减和资源缩减是分开进行的,现在 R8 将这两者结合起来,可以跨越代码和 XML 资源进行全局追踪,如果一个 Activity 的代码被判定为未使用并被移除了,R8 会顺藤摸瓜将它引用的无用 XML 布局、图片资源一并剔除

所以,官方团队也建议所有开发者开启 R8,因为开启 R8 不仅能减小 APK 体积,还能大幅降低后台 ANR 的概率,并显著提升应用启动和运行速度,例如性能团队的 Shai 分享了一个数据:

根据他们与 Top 应用开发者的合作,将一个应用从不使用 R8 优化到全面深度应用 R8,其带来的性能提升效果,相当于给用户的手机免费进行了“3 到 4 年的硬件升级” ,换句话说,运行经过 R8 优化代码的旧手机,体验可以媲美运行未优化代码的最新款手机。

当然,这里的 R8 更多是 full mode 的 R8 ,R8 提供两种模式,兼容模式和全模式,全模式才是满血优化,android.enableR8.fullMode=false 的可不算,例如:

在兼容模式下,R8 不改变类中方法和字段的可见性,而在完全模式下,R8 会通过改变方法和字段的可见性来增强优化,比如将 private to public 从而支持更多内联

总而言之,那就是你需要 R8 ,拥抱 R8 ,All in R8 ,阿巴阿巴阿巴阿巴·····


你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解》 是转载文章,点击查看原文


相关推荐


如何零成本搭建个人站点
mCell2026/2/12

同步至个人站点:如何零成本搭建个人站点 站点地址:stack.mcell.top,包含完整的:写作、评论、部署、MCP支持... 我经常写作,最开始是在一些平台上,比如稀土掘金。后面慢慢写多了,就想有个自己的博客平台。 最初搭建的博客很简单:一个纯静态的 HTML 文件,内容也不复杂,写点自我介绍,当作个人站点。直接托管到 GitHub Pages,域名用的也是它默认那串。 但很快就发现:功能太少了。 比如发布文章?评论?甚至想加点扩展能力都很难——纯 HTML 又没框架,后面越改越痛苦。


PostgreSQL全文检索中文分词器配置与优化实践
MarsBighead2026/2/3

引言 在构建RAG(检索增强生成)系统的过程中,提升检索效率与准确性是一个持续优化的课题。除了常见的嵌入向量检索外,结合全文检索技术能进一步改善系统表现。本文基于PostgreSQL数据库,分享中文全文检索分词器的配置、索引创建与使用实践,记录在真实场景中遇到的问题与解决方案。 一、背景 为了提升RAG系统的检索效果,我们探索了全文检索与向量检索结合的混合检索方案。PostgreSQL内置了强大的全文检索功能,并支持扩展插件实现多语言分词。针对中文场景,我们选用了 zhparser 分词插件,


怎么理解 HttpServletRequest @Autowired注入
それども2026/1/24

在你的代码中,@Autowired(required = false) private HttpServletRequest req 的 required = false 是多余的,甚至可能带来潜在问题。以下是详细分析: 1. 为什么 required = false 是多余的? (1) HttpServletRequest 的特殊性 由 Servlet 容器(如 Tomcat)管理:HttpServletRequest 是 Web 请求的上下文对象,在 Servlet 环境中必然存在(


Objective-C 核心语法深度解析:基本类型、集合类与代码块实战指南
奋斗理想2026/1/16

详细讲解:Objective-C 基本类型、集合类和代码块 一、基本类型详解 1.1 主要基本类型 // MyTypes.m #import <Foundation/Foundation.h> void demonstrateBasicTypes() { NSLog(@"========== 基本类型演示 =========="); // 1. BOOL 类型(实际上是 signed char) BOOL isOpen = YES; // YES = 1,


SPI通信:从原理到工程实践
我太浮躁2026/1/8

文章目录 1、概述2、什么是SPI?2.1 SPI的特点是什么? 3、SPI的历史发展3.1 SPI诞生3.2 为什么是SPI?3.3 SPI的一路升级3.3.1 标准 SPI (Standard SPI)3.3.2 Dual SPI & Quad SPI (QSPI)3.3.3 Octal SPI (OSPI) / xSPI3.3.4 eSPI (Enhanced SPI) 4、协议架构及通信原理4.1 SPI功能层级划分(非官方,但实用便于理解)4.1.1 物理层 :四线制结


[服务器][教程]EC2开启自定义端口
踏雪Vernon2025/12/30

网上很多教程并没有说这一点。直接就说新建安全组之后就可以用了。 很坑,我一直以为我的服务器服务搭建的有问题。因为即使端口开了,端口没有对应的服务用端口扫描也是显示无连接的!! 1. 新建安全组规则 进入“实例”页面中找到“安全组”。新建一个安全组 新建之后如下所示。 新建之后,并不是直接就可以用了。而是要进行绑定!这个一定要注意!!! 2. 修改安全组规则 点击实例之后,选择“操作”,更改安全组 之后在这里选择刚才创建的安全组即可。其他的VPC应该也是类似的。 被网上的教程坑了。大家注意甄


【前端必看】手把手教你把 Strapi 5 自动化部署到宝塔,再也不用手动传代码了!
知航驿站2025/12/21

前言 兄弟们,作为一名普通前端,每次写完接口还要自己登录服务器、手动上传代码、装依赖、再重启 PM2,这一套“广播体操”做下来,天都黑了。 今天咱们就花 10 分钟,把这套活儿交给 GitHub Actions。以后你只管在本地 git push,剩下的脏活累活全让机器人帮你干! 在线文档 在线源码 一、 整体思路(大白话版) 代码放 GitHub:这大家都会。 GitHub Actions 开工:你一推代码,它就跳出来执行一个脚本。 SSH 远程登录:GitHub 像个“代跑腿”的,拿着你的


Webpack打包机制与Babel转译原理深度解析
老前端的功夫2025/12/13

Webpack打包机制与Babel转译原理深度解析 引言:现代前端构建工具的核心原理 Webpack和Babel是现代前端开发不可或缺的两个核心工具。Webpack解决了模块化、资源管理和打包优化的难题,而Babel则确保了JavaScript代码的浏览器兼容性。理解它们的底层原理不仅有助于更好地配置和使用这些工具,还能在遇到复杂问题时快速定位和解决。 一、Webpack打包机制深度解析 1.1 Webpack核心概念与架构设计 Webpack的整体架构: // Webpack 的核心抽象概念


TRAE SOLO 驱动:重构AI模拟面试产品的复盘
HiStewie2025/12/4

面试是一项技能,而任何技能的进阶都离不开“高频练习”与“即时反馈”这两个核心要素。 传统的面试准备往往陷入两个极端:要么对着镜子自言自语,缺乏客观的第三方视角;要么花重金找导师模拟,成本高昂且难以常态化。技术存在的意义,就是用低边际成本解决高频痛点。 但这其实并不是我第一次尝试解决这个问题。在此之前,我曾开发过一个初版工具:(QuizPort1.0 让每篇好文都有测验陪跑) 当时的思路很线性:抓取技术文章 →\rightarrow→ AI 提炼知识点 →\rightarrow→ 生成文字面试题


【AI个人学习】npm本地安装claude code白嫖minimax模型
汐瀼2026/2/28

安装nodejs 下载 需要自取,下一步傻瓜式操作 通过网盘分享的文件:node-v24.13.0-x64.msi 链接: https://pan.baidu.com/s/1eJhCowFZ211oV2yxAfPvQA?pwd=sayg 提取码: sayg –来自百度网盘超级会员v7的分享 系统变量添加全局包路径 打开CMD敲命令 npm config get prefix # 获取npm全局包路径,获取后复制 添加路径到系统变量即可,添加系统变量网上教程一大堆 安装claude

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客