Android性能优化之Android 10+ dex2oat实践

本文探讨了Android 10+中dex2oat性能优化面临的挑战,包括系统限制导致的编译问题。通过分析限制原因和尝试绕过限制,最终找到了借助系统本身触发编译的解决方案。实践结果显示,优化后Dex加载速度提升显著,提高了用户体验。
摘要由CSDN通过智能技术生成

作者:字节跳动终端技术——郭海洋

背景

对于Android App的性能优化来说,方式方法以及工具都有很多,而dex2oat作为其中的一员,却可能不被大众所熟知。它是Android官方应用于运行时,针对dex进行编译优化的程序,通过对dex进行一系列的指令优化、编译机器码等操作,提升dex加载速度代码运行速度,从而提升安装速度、启动速度、以及应用使用过程中的流畅度,最终提升用户日常的使用体验。

它的适用范围也比较广,可以用于Primary ApkSecondary Apk常规场景插件场景。(Primary Apk是指的常规场景下的主包base.apk)或者插件场景下的宿主包Secondary Apk是指的常规场景下的自行加载的包(.apk)或者插件场景下的插件包(.apk))。

而随着Android系统版本的更迭,发现原本可以在应用进程上触发dex2oat编译的方式,却在targetSdkVersion>=29Android 10+的系统上,不再允许使用。其原因是系统在targetSdkVersion=29的时候,对此做了限制,不允许应用进程上触发dex2oat编译(Android 运行时 (ART) 不再从应用进程调用 dex2oat。这项变更意味着 ART 将仅接受系统生成的 OAT 文件)(OATdex2oat后的产物)。

那当前是否会受到这个限制的影响呢?

2020年的时候Android 11系统正式发布,各大应用市场就开始限制ApptargetSdkVersion>=29,而Android 11系统距今已经发布一年之久,也就意味着,现如今ApptargetSdkVersion>=29是不可避免的。而且随着新Android设备的不断迭代,越来越多的用户,使用上了携带新系统的新机器,使得Android 10+系统的占有量逐步增加,目前为止Android 10+系统的占有量约占整体的30%~40%左右,也就是说这部分机器将会受到这个限制的影响。

那这个限制有什么影响呢?

这个限制的关键是,不允许应用进程上触发dex2oat编译,换句话说就是并不影响系统自身去触发dex2oat编译,那么限制的影响也就是,影响那些需要通过应用进程去触发dex2oat编译的场景。

对于Primary ApkSecondary Apk,它们在常规场景插件场景下,系统都会收集其运行时的热点代码并用于dex2oat进行编译优化。此处触发dex2oat编译是系统行为,并不受限于上述限制。但触发此处dex2oat编译的条件是比较苛刻的,它要求设备必须处于空闲状态且要连接电源,而且其校验的间隔是一天。

在上述条件下,由系统触发的dex2oat编译,基本上很难触发,从而导致dex加载速度下降80%以上,代码运行速度下降11%以上,使得应用的ANR率提升、流畅度下降,最终影响用户的日常使用体验。

对于之前来说改进方案就是通过应用进程触发dex2oat编译来弥补系统触发dex2oat编译的不足,而如今因限制会导致部分机器无法生效。

如何才能让用户体会到dex2oat带来的体验提升呢?问题又如何解决呢?

下面通过探索,一步步的逼近真相,解决问题~

探索

探索之前,先明确下核心点,本次探索的目标就是为了让用户体会到dex2oat带来的体验提升,其最大的阻碍就是系统触发dex2oat的编译条件太苛刻,导致难以触发,之前的成功实践就是基于App维度手动触发dex2oat编译来弥补系统触发dex2oat的编译的不足。

而现在仍需探索的原因就是,原本的成功实践,目前在某些机器上已经受限,为了完成目标,解决掉现有的问题,自然而然的想法就是,限制究竟是什么?限制是如何生效的?是否可以绕过?

限制是什么?

目前对于限制的理解,应该仅限于背景中的描述,那Google官方是怎么说的呢?

Android 运行时 (ART) 不再从应用进程调用 dex2oat。这项变更意味着 ART 将仅接受系统生成的 OAT 文件。(Android 运行时只接受系统生成的 OAT 文件

通过Google官方的描述大致可以理解为,原本ART会从应用进程调用dex2oat,现在不再从应用进程调用dex2oat了,从而使得应用进程没有时机触发dex2oat,从而达到限制App维度触发dex2oat的目的。

但问题确实有这么简单嘛?

通过对比Android 9Android 10的代码时发现,Android 9在构建ClassLoader的时候会触发dex2oat,但是 Android 10 上相关代码已经被移除,此处同Google官方的说法一致。

但如果限制仅仅如此的话,可以按照原本ART从应用进程调用dex2oat的方式,然后手动从应用进程调用就可以了。

由于Android`` ``10相关代码已经移除,所以查看下Android 9的代码,看下之前是如何从应用进程调用dex2oat的,相关代码链接:https://android.googlesource.com/platform/art/+/refs/tags/android-9.0.0_r52/runtime/oat_file_assistant.cc#698,通过查看代码可以看出,是通过拼接dex2oat的命令来触发执行的,按照如上代码,拼接dex2oat命令的伪代码如下:

//step1 拼接命令

List<String> commandAndParams = new ArrayList<>();

commandAndParams.add("dex2oat");

if (Build.VERSION.SDK_INT >= 24) {

    commandAndParams.add("--runtime-arg");

    commandAndParams.add("-classpath");

    commandAndParams.add("--runtime-arg");

    commandAndParams.add("&");

}

commandAndParams.add("--instruction-set=" + getCurrentInstructionSet());

// verify-none|interpret-only|verify-at-runtime|space|balanced|speed|everything|time

//编译模式,不同的模式,影响最终的运行速度和磁盘大小的占用

if (mode == Dex2OatCompMode.FASTEST_NONE) {

    commandAndParams.add("--compiler-filter=verify-none");

} else if (mode == Dex2OatCompMode.FASTER_ONLY_VERIFY) {

    //快速编译

    if (Build.VERSION.SDK_INT > 25) {

        commandAndParams.add("--compiler-filter=quicken");

    } else 
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值