android虚拟机 Dalvik & ART

ART VS. Dalvik

Dalvik虚拟机是2008年跟随Android系统一起发布的。当时的移动设备的系统内存只有64M左右,CPU频率在250~500MHz之间。这个硬件水平早已发生了巨大变化。随着智能设备的兴起,这些年移动芯片的性能每年都有大幅提升。如今的智能手机内存已经有6G甚至8G至多。CPU也已经步入了64位的时代,频率高达2.0 GHz甚至更高。硬件的更新,常常也伴随着软件的换代。因此,Dalvik虚拟机被淘汰也是情理之中的事情。

Dalvik之所以要被ART替代包含下面几个原因:

  • Dalvik是为32位设计的,不适用于64位CPU。
  • 单纯的字节码解释加JIT编译的执行方式,性能要弱于本地机器码的执行。
  • 无论是解释执行还是JIT编译都是单次运行过程中发生,每运行一次都可能需要重新做这些工作,这样做太浪费资源。
  • 原先的垃圾回收机制不够好,会导致卡顿。

很显然,ART虚拟机对上面提到的这些地方做了改进。除了支持64位不必说,最主要的是下面两项改进:

  • AOT编译:Ahead-of-time(AOT)是相对于Just-in-time(JIT)而言的。JIT是在运行时进行字节码到本地机器码的编译,这也是为什么Java普遍被认为效率比C++差的原因。无论是解释器的解释还是运行过程中即时编译,都比C++编译出的本地机器码执行多了一个耗费时间的过程。而AOT就是向C++编译过程靠拢的一项技术:当APK在安装的时候,系统会通过一个名称为dex2oat的工具将APK中的dex文件编译成包含本地机器码的oat文件存放下来。这样做之后,在程序执行的时候,就可以直接使用已经编译好的机器码以加快效率。

  • 垃圾回收的改进:GC(Garbage Collection)是虚拟机非常重要的一个特性,因为它的实现好坏会影响所有在虚拟机上运行的应用。GC实现得不好可能会导致画面跳跃,掉帧,UI响应过慢等问题。ART的垃圾回收机制相较于Dalvik虚拟机有如下改进:

    • 将GC的停顿由2次改成1次
    • 在仅有一次的GC停顿中进行并行处理
    • 在特殊场景下,对于近期创建的具有较短生命的对象消耗更少的时间进行垃圾回收
    • 改进垃圾收集的工效,更频繁的执行并行垃圾收集
    • 对于后台进程的内存在垃圾回收过程进行压缩以解决碎片化的问题

AOT编译是在应用程序安装时就进行的工作,下图描述了Dalvik虚拟机与(Android 5.0上的)ART虚拟机在安装APK时的区别:

art_vs_dalvik.png

两种虚拟机上安装APK时的流程

从这幅图中我们看到:

  • 在Dalvik虚拟机上,APK中的Dex文件在安装时会被优化成odex文件,在运行时,会被JIT编译器编译成native代码。
  • 而在ART虚拟机上安装时,Dex文件会直接由dex2oat工具翻译成oat格式的文件,oat文件中既包含了dex文件中原先的内容,也包含了已经编译好的native代码。

dex2oat生成的oat文件在设备上位于/data/dalvik-cache/目录下。同时,由于32位和64位的机器码有所区别,因此这个目录下还会通过子文件夹对oat文件进行分类。例如,手机上通常会有下面两个目录:

  • /data/dalvik-cache/arm/
  • /data/dalvik-cache/arm64/

image.png

扫描二维码关注公众号,回复: 13165069 查看本文章

image.png

image.png

Profile Guided Compilation

JIT的执行时机需要一套追踪机制来决定哪一部分代码需要被执行JIT-也就是热区域的确定,这个追踪技术在Android中被成为Profile Guided Compilation。

Profile Guided Compilation的工作原理:

  • step1,应用程序第一次启动时,只会通过解释器执行,同时JIT会介入并针对hot methods执行优化工作。

  • step2,第一步的执行过程中会同步输出一种被称为profile information的信息保存到文件中。

  • step3,上述步骤会重复执行,以使profile information不断完善,profile information中记录了需要离线优化的函数hot methods,影响程序启动速度的Classes,以进一步优化程序的启动速度,等等。

  • step4,当设备处于idle状态并且在充电,就会进入profile guided compilation服务,这个编译过程以profile information文件为输入,输出是二进制机器码,这里的二级制机器码被用于替代原始应用程序的相应部分。

  • step5,经过前面的步骤,应用程序在后续启动时,就可以根据实际情况在AOT/JIT/Interpreter中选择最合适的执行方式了。

Profiles in the Cloud:

从N开始使用profile方式编译,对于存储空间、内存、功耗、CPUs使用率都有益处,但目前profile只是本地的方式, 在优先之前仍需要等待获取profile。未来收集用户的profile,并上传到云端(Google play),在安装时从云端获取profile直接使用到新用户。 大概能提升20%的冷启动性能。

参考:

  1. Android上的ART虚拟机
  2. Android ART虚拟机执行引擎-JIT(九)
  3. 系统角度解读Android P新特性

猜你喜欢

转载自juejin.im/post/7016888288753483812