Android VM 01 JVM 、DVM、ART简介

1.DVM与JVM的区别

  • JVM基于栈,DVM基于寄存器

寄存器是 CPU 上面的一块存储空间,栈是内存上面的一段连续的存储空间。

  • DVM 执行的 .dex 文件,JVM 执行 .class 文件。
  • DVM:允许运行多个虚拟机实例,每一个应用启动都运行一个单独的虚拟机,并且运行在一个独立的进程中JVM:只能运行一个实例,也就是所有应用都运行在同一个 JVM 中

Java虚拟机使用的指令只占一个字节,因而称为字节码。基于寄存器的指令由于需要指定源地址和目标地址,因此需要占用更多的指令空间。Dalvik虚拟机的某些指令需要占用两个字节。基于栈和基于寄存器的指令集各有优劣,一般而言,执行同样的功能,前者需要更多的指令(主要是load和store指令),而后者需要更多的指令空间。需要更多指令意味着要多占用CPU时间,而需要更多指令空间意味着数据缓冲(d-cache)更易失效

.dex 和 .class区别

dex 和 class文件区别

dex格式文件使用共享的、特定类型的常量池机制来节省内存。常量池存储类中的所有字面常量,它包括字符串常量、字段常量等值。

2.Davilk虚拟机

2.1 Davilk做出的优化

  • 将多个类文件收集到同一个dex文件中,以便节省空间;
  • 使用只读的内存映射方式加载dex文件,以便可以多进程共享dex文件,节省程序加载时间;
  • 提前调整好字节序(byte order)和字对齐(word alignment)方式,使得它们更适合于本地机器,以便提高指令执行速度;
  • 尽量提前进行字节码验证(bytecode verification),提高程序的加载速度;
  • 需要重写字节码的优化要提前进行。

2.2 Davilk执行流程

Davilk执行流程

一个应用首先经过DX工具将class文件转换成Dalvik虚拟机可以执行的dex文件,然后由类加载器加载原生类和Java类,接着由解释器根据指令集对Dalvik字节码进行解释、执行。最后,根据dvm_arch参数选择编译的目标机体系结构

2.3 JIT

JIT(Just In Time Compiler, 即时编译),Android 2.2 版本提出的

image

JIT 模式的缺点:
  • 每次启动应用都需要重新编译
  • 运行时比较耗电,造成电池额外的开销
系统编译中控制JIT的位置

/build/target/product/runtime_libart.mk

1
2
3
4
5
6
7
8
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += \
dalvik.vm.image-dex2oat-Xms=64m \
dalvik.vm.image-dex2oat-Xmx=64m \
dalvik.vm.dex2oat-Xms=64m \
dalvik.vm.dex2oat-Xmx=512m \
ro.dalvik.vm.native.bridge=0 \
dalvik.vm.usejit=true \
dalvik.vm.usejitprofiles=true \

JIT 虚拟机执行的本地机器码:

.java –> java bytecode(.class) –> dalvik bytecode(.dex) –> optimized dalvik bytecode(.odex)

#####

  • DEX means Dalvik EXcutable file.
  • ODEX means Optimized Dalvik EXcutable file.

2.4 Dex文件

dex结构

  • header:存储了各个数据类型的起始地址、偏移量等信息。
  • proto_ids:描述函数原型信息,包括返回值,参数信息。比如“test:()V”
  • methods_ids:函数信息,包括所属类及对应的proto信息。

https://blog.csdn.net/joye123/article/details/78379109

虽然dex文件的结构很紧凑,但想要运行时的性能得到进一步提升,还需要对dex文件进行进一步优化。

dex优化

  • 调整所有字段的字节序和对齐结构中的每一个域
  • 验证dex文件中的所有类
  • 对一些特定的类进行优化,对方法里的操作码进行优化

3.ART

ART 即 Android Runtime。在 ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译( AOT, Ahead-Of-Time )

ART 虚拟机执行的本地机器码:

.java –> java bytecode(.class) –> dalvik bytecode(.dex) –> optimized android runtime machine code(.oat)

3.1 ART 对 Garbage Collection(GC)过程的改进:

  • 只有一次 GC 暂停(Dalvik 需要两次)
  • 在 GC 保持暂停状态期间并行处理
  • 在清理最近分配的短时对象这种特殊情况中,回收器的总 GC 时间更短
    优化了垃圾回收的工效,能够更加及时地进行并行垃圾回收,这使得 GC_FOR_ALLOC 事件在典型用例中极为罕见
  • 压缩 GC 以减少后台内存使用和碎片

AOT 模式解决了应用启动和运行速度和耗电问题的同时也带来了另外两个问题:

  • 应用安装和系统升级之后的应用优化比较耗时
  • 优化后的文件会占用额外的存储空间

3.2 OAT文件

image

从这个图中我们看到,OAT文件中包含的内容有:

  • ELF Header:ELF头信息。
  • oatdata symbol:oatdata符号,其地址指向了OAT头信息。
  • Header:Oat文件的头信息,详细描述了Oat文件中的内容。例如:Oat文件的版本,Dex文件个数,指令集等等信息。Header,Dex File数组以及Class Metadata数组都位于ELF的只读数据段.rodata中。
  • Dex File数组:生成该Oat文件的Dex文件,可能包含多个。
  • Class Metadata数组:Dex中包含的类的基本信息,可能包含多个。通过其中的信息可以索引到编译后的机器码。
  • 编译后的方法代码数组:每个方法编译后对应的机器码,可能包含多个。这些内容位于代码段(.text)中。

3.3 AOT 和 JIT 的不同

JIT 是在运行时进行编译,是动态编译,并且每次运行程序的时候都需要对 odex 重新进行编译;而 AOT 是静态编译,应用在安装的时候会启动 dex2oat 过程把 dex 预编译成 ELF 文件,每次运行程序的时候不用重新编译,是真正意义上的本地应用

3.4 dexopt 与 dex2oat 区别

image

  • dexopt 是对 dex 文件 进行 verification 和 optimization 的操作,其对 dex 文件的优化结果变成了 odex 文件,这个文件和 dex 文件很像,只是使用了一些优化操作码(譬如优化调用虚拟指令等)。

  • dex2oat 是对 dex 文件的 AOT 提前编译操作,其需要一个 dex 文件,然后对其进行编译,结果是一个本地可执行的 ELF 文件,可以直接被本地处理器执行。

dexopt was used to optimize DEX to ODEX (optimized DEX) which contains the optimized bytecode.

With AOT, dex2oat is used to optimize and compile DEX into an OAT file which may contain machine code in the ELF format.

3.5 Android系统对预编译的处理

  • 编译的时候针对user版本会对apk进行处理,将里面的class.dex文件拿出来单独处理为odex,apk文件中只留下一些资源文件

  • 第一次开机耗时会比较长,中间有大量的dex2oat的log存在,也是针对每个APK在做dex优化

LOCAL_DEX_PREOPT

这个变量设置为false可以使整个系统使用提前优化的时候,某个app不使用提前优化。在Android.mk中给该变量赋值为false,则编译生成的文件没有oat文件,也就意味着没有被提前优化。


Android 7.0 AOT/JIT 混合编译模式

image

混合编译模式的特点是:
  • 应用在安装的时候 dex 不会被编译
  • 应用在运行时 dex 文件先通过解析器(Interpreter)后会被直接执行(这一步骤跟 Android 2.2 - Android 4.4之前的行为一致),与此同时,热点函数(Hot Code)会被识别并被 JIT 编译后存储在 jit code cache 中并生成 profile 文件以记录热点函数的信息。
  • 手机进入 IDLE(空闲) 或者 Charging(充电) 状态的时候,系统会扫描 App 目录下的 profile 文件并执行 AOT 过程进行编译。

Android 8.0

Android O 版本中,将会生成以下文件:

  • .vdex:其中包含 APK 的未压缩 DEX 代码,以及一些旨在加快验证速度的元数据。
  • .odex:其中包含 APK 中已经过 AOT 编译的方法代码。
  • .art (optional):其中包含 APK 中列出的某些字符串和类的 ART 内部表示,用于加快应用启动速度。

Dalvik Optimization and Verification With dexopt

Dalvík and ART. Jonathan Levin

配置Art

理解Android虚拟机体系结构(转)

Dalvik虚拟机简要介绍和学习计划