1、虚拟机

1.1、Android虚拟机编年史

img

Android虚拟机主要有两种:Davlik和Art,Art在Android L后正式成为了默认的虚拟机;有点年岁的用户可能经历过可以在开发者选项切换虚拟机的时代🐶

JIT vs AOT

JIT(just in time):在运行时编译,边运行边编译。每启动一个应用程序,都会相应地启动一个 dalvik 虚拟机,启动时会建立JIT 线程,一直在后台运行。当某段代码被调用时,虚拟机会判断它是否需要编译成机器码,如果需要,就做一个标记,JIT 线程不断判断此标记,如果发现被设定就把它编译成机器码,并将其机器码地址及相关信息放入 entry table 中,下次执行到此就跳到机器码段执行,而不再解释执行,从而提高速度。【运行时优化】 img AOT(ahead of time):在APK安装的时候就会做预先编译动作,编译好的文件是OAT文件,该文件本质上是一个ELF文件,它是可以直接被执行的文件。【编译时优化】 img 混合运行时:Android N后Google探索了一个结合JIT和AOT的混合策略:

  • 应用在安装时不做编译,而是解释字节码,所以可以快速启动
  • JIT的数据被分析并保存(profile文件),在设备空闲、充电时进行AOT编译 img

1.2、虚拟机和字节码

img

  • 传统的jvm:.java–[javac]–>.class
  • Android虚拟机:.java–[javac]–>.class–[dx]–>.dex

Dalvik vs Art img

2、dex、odex以及vdex

2.1、dex文件

img

img

基于栈的虚拟机 VS 基于寄存器的虚拟机

2.2、odex(optimized dex)文件

Dalvik VM:apk文件的本质是zip包,字节码分布在其中的classes*.dex内,为了优化每次unzip和一些依赖的耗时,Dalvik下会通过dexopt将apk中的dex抽出,优化成odex文件,存在/data/dalvik-cache/下(并且会删除apk内dex);这样带来三个主要好处:

  • 启动时不需要解压apk获取dex文件了 → 启动耗时优化
  • 同一时刻一个应用不会存在两份dex了 → 内存占用优化
  • apk不包括dex了,提取或者反编译难度变大 → 安全优化

Art VM:在Art虚拟机下,odex文件本质是oat文件,也就是可以被linux底层直接运行的可执行文件。Art下会通过dex2oat将apk中的dex优化成odex(oat文件)。

ELF&OAT ELF(Executable and Linking Format)是一种对象文件的格式,用于定义不同类型的对象文件(Object files)中都放了什么东西、以及都以什么样的格式去放这些东西。它自最早在 System V系统上出现后,被 xNIX 世界所广泛接受,作为缺省的二进制文件格式来使用。可以说,ELF 是构成众多 xNIX 系统的基础之一。 OAT文件是一种Android私有ELF文件格式,它不仅包含有从DEX文件翻译而来的本地机器指令,还包含有原来的DEX文件内容。APK在安装的过程中,会通过dex2oat工具生成一个OAT文件。对于apk来说,oat文件实际上就是对odex文件的包装,即oat=odex,而对于一些framework中的一些jar包,会生成相应的oat尾缀的文件

2.2、vdex(verified dex)

Android O(8.0)后,为了降低dex2oat的耗时、避免不必要的验证Dex文件合法性的过程,Android引入了vdex机制。

  • Vdex = dex + quicken info

而这时候dex2oat再也不是直接从dex生成odex了,而是从vdex中抽取文件生成odex

  • 全部源码 = vdex + odex

3、dex2oat

上面两个章节我们回顾Android虚拟机的一些事情,知道了在目前主流的Art虚拟机下通过AOT技术会将vdex转换成odex文件,这样可以有效的提高应用的执行效率。而这个转化过程正是通过系统的dex2oat工具完成的,这个章节会来了解一下dex2oat相关的知识。

3.1、触发时机

img

3.2、编译级别

img

img

我们知道vdex+odex=全部代码,当odex越大,vdex越小时,我们优化编译的效果也越好;所以上面的编译级别也会遵循占用空间越大,编译优化效果越好的原则,主要几个级别编译效果:

verify<space<speed<everything

在Android N后由于混合模式的采用,多出了几个**-profile的模式;这里主要涉及到profile文件的生成,篇幅原因可以参考Android profile-guided dex2oat_大将军王虎剩的专栏中的profile-guide内容。

profile文件:/data/misc/profiles/cur/0/com.***.home/primary.prof 每个app的profile文件都在 /data/misc/profiles/ 目录下。profile文件用来记录运行比较频繁的代码,用来进行 profile-guide 编译,使得 dex2oat编译代码更精准。 profile的创建 App安装的过程中,会调用到 isntalld的 create_app_data()函数, 如果当前支持profile编译,则会为app创建 profile文件。

查看系统定义的几个场景的编译级别

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
→ adb shell getprop

...

[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]: [speed-profile]

[pm.dexopt.shared]: [speed]

REF:

[1] Android虚拟机的JIT编译器

[2] Dalvik,ART与ODEX相爱相生

[3] Android dex,odex,oat,vdex,art文件结构学习总结