美文网首页
android 基础-Dalvik ,ART,JIT,AOT,D

android 基础-Dalvik ,ART,JIT,AOT,D

作者: kotlon | 来源:发表于2020-08-27 17:26 被阅读0次

Dalvik 和 ART

Dalvik:Dalvik 虚拟机,android 5.0 以前所使用的虚拟机,可执行文件为 dex 格式,基于寄存器的虚拟机(jvm 基于堆栈)。通过 dx 工具将 .class 文件转换为 .dex 格式。

ART:android rutime,android 5.0 以后使用的虚拟机。

关于这个虚拟机的点,希望了解的关注点在于虚拟机这块。

ios 和 android对比,android 是基于虚拟机的,android 开发者使用 kotlin/java 编写代码(java 是编译-解释性语言),最终会编译成 .class 文件,.class 文件经过 dx 工具会优化成 dex 格式文件,dex 格式文件可以在虚拟机上执行。ios 开发者通过编写 Objective-C 或者 Swift 语言,是直接编译为机器码的。基于这点,ios 原生要比 android 存在优势。

但是随着编译技术的发展,两者的性能差距越来越小,甚至基本持平。

Dex 文件

java 代码通过 java 编译器生产 .class 文件,.class 文件在通过 dx 工具,生产 dex 文件。dex 格式的详细说明如链接:dex 文件格式

JIT

JIT:Just In Time Compiler 及时编译技术。关注这个及时编译的含义。android 系统上, dex 文件 并不直接在系统层面执行的, davlik 负责解释 dex,并且生成操作系统可以执行的微指令。

jit 存在的缺陷:

  1. 每次启动都需要重新编译
  2. 运行时耗电量大

AOT

JIT 是即时编译,是动态编译,可以对执行次数频繁的 dex 代码进行编译和优化,减少使用时的编译时间,虽然可以提高执行性能,但是本身编译需要耗费时间。Google 在 5.0 之后使用 ART 替代 Dalvik,包括了 AOT 的使用。

AOT 是静态编译。应用安装过程中,会使用 dex2oat 工具,把 dex 预编译成 ELF 文件,每次运行过程不用重新编译。

android 编译过程的发展

android 2.2

早期的android 支持 jit 编译,通过 JIT 优化编译。但是显然存在问题

  • 每次启动之后,都要进行 JIT 编译
  • 如果执行没有进行 JIT 编译的代码,还是得不到优化效果

具体的 JIT 的流程,参考 android 7.0 的说明。

android 5.0

5.0 以后,google 使用了 新的 ART 虚拟机,在 ART 虚拟机上,使用 AOT 把字节码dex/odex 优化成可执行的字节码 ELF 文件。可是这样也会带来新的问题。

  • 每次 app 升级,都要重新进行 OAT 操作
  • 每次系统升级 也要进行 OAT 操作
  • OAT 操作需要额外的存储空间

android 7.0

android 7.0 之后,google 醒悟了,使用了AOT + JIT 的混合编译模式;具体策略如下:

  • app 首次安装,dex 不会通过 AOT 优化
  • app 运行期间,dex 文件通过解析器被直接执行,热点函数会被识别,并且被 JIT 编译后存在 JIT Code Cache,并且生成 profile 文件以记录热点函数的信息
  • 手机进入空闲状态,系统会扫描 appp 目录下的 profile 文件, 并且执行 AOT 过程

这样就能够避免了首次安装的等待,同时进行代码优化。
具体的 profile 文件的逻辑,参考我后面的文章。

ART 包括一个编译器工具(dex2oat工具),dex2oat 会根据 dex 文件生成一个或者多个编译工具文件,具体的可能有不同版本差异,在 android O版本下,有以下文件:

  • .vdex :包含了 APK 未压缩的 DEX 代码,以及一些加快验证速度的元数据
  • .odex:包括了经过 AOT 编译优化的代码
  • .art:包含了 APK 中累出字符串和类的 ART 内部表示,用于加快启动速度

ART 进行编译结构如下图

jit-workflow.png
  1. 用户运行应用,此举随后触发 ART 加载.dex 文件。
    • 如果有 .oat 文件(即 .dex 文件的 AOT 二进制文件),ART 会直接使用该文件。虽然 .oat 文件会定期生成,但文件中不一定会包含经过编译的代码(即 AOT 二进制文件)。
    • 如果 .oat 文件不含经过编译的代码,ART 会通过 JIT 和解释器执行 .dex 文件。
  2. 针对任何未根据 speed 编译过滤器编译的应用启用 JIT(也就是说,要尽可能多地编译应用中的代码)。
  3. 将 JIT 配置文件数据转储到只有该应用可以访问的系统目录下的文件中。
  4. AOT 编译 (dex2oat) 守护程序通过解析该文件来推进其编译。

android 8.0

android 8.0 改进优化解释器速度。

android 9.0

android 9.0 之后,改进模板代码,简单来说,就是同样的代码,不同的编译模板生产的机器码不一样,android 在 9.0 优化了 vm 模板。

但是 vm 模板没有针对 不同 app 进行优化。

Dex2oat

Dex2oat 是 ART 里面的一个编译工具;

ART 的编译选项,分为两种类型:

  1. 系统 ROM 配置:编译系统映像时,会对哪些代码进行 AOT 编译
  2. 运行时配置:ART 如何在设备上编译和允许应用

编译配置,也就是传递给 dex2oat 存在四个参数:

  1. verify:只运行 DEX 代码验证
  2. quicken:运行 DEX 代码验证,并优化一些 DEX 指令,以获得更好的编译器性能
  3. speed: 运行 Dex 代码验证,并对所有的方法进行 AOT 编译。
  4. speed-profile:运行 DEX 代码验证,并对配置文件列出的方法进行 AOT 编译。

有许多 ART 构建选项可用于配置系统 ROM。如何配置这些选项取决于 /system 的可用存储空间以及预安装应用的数量。编译到系统 ROM 中的 JAR/APK 可以分为以下四个类别:

  • 启动类路径代码:默认使用 speed 编译过滤器进行编译。
  • 系统服务器代码:默认使用 speed 编译过滤器进行编译。
  • 产品专属的核心应用:默认使用 speed 编译过滤器进行编译。
  • 所有其他应用:默认使用 quicken 编译过滤器进行编译。

怎么验证手机上使用的编译模式?先 根据

adb shell

进入 adb shell ,再执行命令:

getprop | grep pm

getprop 是读取配置文件的意思,grep 是过滤选项,pm 是 package manager 的意思,最终如下:

PD1818:/ $ getprop | grep pm
[dalvik.vm.heapmaxfree]: [8m]
[dalvik.vm.heapminfree]: [4m]
[dev.pm.dyn_samplingrate]: [1]
[init.svc.dpmQmiMgr]: [running]
[init.svc.dpmd]: [running]
[persist.vendor.dpm.feature]: [11]
[persist.vendor.dpm.tcm]: [2]
[persist.vendor.radio.apm_sim_not_pwdn]: [1]
[pm.dexopt.ab-ota]: [speed-profile]
[pm.dexopt.bg-dexopt]: [speed-profile]
[pm.dexopt.boot]: [verify]
[pm.dexopt.first-boot]: [quicken]
[pm.dexopt.inactive]: [verify]
[pm.dexopt.install]: [quicken]
[pm.dexopt.shared]: [speed]

例如 pm.dexopt.first-boot 这个选项是 quicken,也是是这个手机对第一次启动的 app 采用 quick 模式编译,只验证 dex ,以及优化一些 dex 指令。pm.dexopt.bg-dexopt 模式下,则采用 speed-profile 模式,会根据配置文件进行 AOT 编译。

DexLayout

DexLayout 是 android 8.0 中引入的一个库,用于分析 dex 文件,并且根据配置文件进行重新排序。

默认的 apk 文件,等于 zip 包,zip 压缩工具默认按照文件名对文件进行排列。 Dexlayout 在app 运行期间会收集配置文件信息,然后在设备空闲的时候,把经常一起访问的文件集中在一起,对 dex 文件进行重新排序,可以改变文件位置,从而优化内存访问模式,进而节省 RAM 并且缩短启动时间。

综述

了解那么多一些底层的东西,那么实际涉及到的技术点是怎么样的?包括

  1. 热修复,类似 tinker 就是直接修改 dex
  2. 启动优化,除了优化业务代码, 包括 face book redex 或者 google 官方提供 pgo 操作,也是通过编译层面去优化启动速度的。

app 启动,是一个特别长久复杂的事情,需要了解各方面的知识才能把这个事情做得彻底。

参考资料:

Android Runtime (ART) 和 Dalvik

实现 ART 即时 (JIT) 编译器

配置 ART

Android dex(关于Dalvik、ART、DEX、ODEX、JIT、AOT、OAT)

Android 8.0 中的 ART 功能改进

相关文章

网友评论

      本文标题:android 基础-Dalvik ,ART,JIT,AOT,D

      本文链接:https://www.haomeiwen.com/subject/lrqhsktx.html