虚拟机,提到虚拟机,大家可能第一反应就是java中好像有虚拟机这个玩意。但是安卓中的虚拟机是什么呢?是和java一样的吗?那么我们先来了解一下java中的JVM!

JVM,搞java的肯定对它了解不少。JVM本质上就是一个软件,是计算机硬件的一层软件抽象,在这之上才干够运行Java程序,JAVA在编译后会生成相似于汇编语言的JVM字节码,与C语言编译后产生的汇编语言不同的是,C编译成的汇编语言会直接在硬件上跑。但JAVA编译后生成的字节码是在JVM上跑,须要由JVM把字节码翻译成机器指令。才干使JAVA程序跑起来。JVM运行在操作系统上,屏蔽了底层实现的差异。从而有了JAVA吹嘘的平台独立性和Write Once Run Anywhere。依据JVM规范实现的详细虚拟机有几十种,主流的JVM包括Hotspot、Jikes RVM等。都是用C/C++和汇编编写的,每一个JRE编译的时候针对每一个平台编译。因此下载JRE(JVM、Java核心类库和支持文件)的时候是分平台的,JVM的作用是把平台无关的.class里面的字节码翻译成平台相关的机器码,来实现跨平台。

说白了,简单点,就是:

                                                                      Java

                                                                      .java文件 -> .class文件 -> .jar文件

最后执行是class文件,有的会被再次打包成jar文件。

了解了这些之后,我们再去了解Android 中的虚拟机。

一、Dalvik虚拟机

Dalvik虚拟机( Dalvik Virtual Machine ),简称Dalvik VM或者DVM。这就是Android中的虚拟机。最初它的产生,是因为Google为了解决与Oracle之间关于Java相关专利和授权的纠纷,开发了DVM。

Android既然存在虚拟机,肯定也是在这个DVM上执行的。它的执行流程和JVM很像:

                                                                       Android

                                                                      .java文件 –> .class文件 -> .dex文件->.apk

DVM执行的是.dex格式文件,JVM执行的是.class文件,android程序编译完之后生产.class文件,然后,dex工具会把.class文件处理成.dex文件,然后把资源文件和.dex文件等打包成.apk文件,apk就是android package的意思。

除了上面所说的,专利授权的原因除外,其实还有因为如下原因:

    dvm是基于寄存器的虚拟机,而jvm是基于虚拟栈的虚拟机。寄存器存取速度比栈快得多,dvm可以根据硬件实现最大的优化,比较适合移动设备。

    class文件存在很多的冗余信息,dex工具会去除冗余信息,并把所有的.class文件整合到.dex文件中,减少了I/O操作,提高了类的查找速度。

不光是上面这些差异,还有运行环境。  

   Dalvik : 一个应用启动都运行一个单独的虚拟机运行在一个单独的进程中

   JVM: 只能运行一个实例, 也就是所有应用都运行在同一个JVM中

 这个是早先的安卓虚拟机,运行速度还是相当慢的。基于寄存器的虚拟机允许更快的执行时间,但代价是编译后的程序更大。于是新的Dex字节码格式odex产生了。它的作用等同于dex,只不过是dex优化后的格式。在App安装的过程中,会通过Socket向/system/bin/install进程发送dex_opt的指令,对Dex文件进行优化。在DexClassLoader动态加载Dex文件时,也会进行Dex的优化,形成odex文件。

为了适应硬件速度的提升,随后在Android 2.2的DVM中加入了JIT 编译器(Just-In-Time Compiler)。Dalvik 使用 JIT 进行即时编译,借助 Java HotSpot VM,JIT 编译器可以对执行次数频繁的 dex/odex 代码进行编译与优化,将 dex/odex 中的 Dalvik Code(Smali 指令集)翻译成相当精简的 Native Code 去执行,JIT 的引入使得 Dalvik 的性能提升了 3~6 倍。

JIT编译器的引入,提升了安装速度,减少了占用的空间,但随之带来的问题就是:多个dex加载会非常慢;JIT中的解释器解释的字节码会带来CPU和时间的消耗;还有热点代码的Monitor一直在运行带来电量的损耗。

 这种情况下,手机动不动就卡是难以避免的。相信各位如果那时候用着Android手机,一定印象非常深刻。因为并不是那么好用。

这样的状况一直持续到Andorid 4.4,带来了全新的虚拟机运行环境 ART(Android RunTime)的预览版和全新的编译策略 AOT(Ahead-of-time)。但那时候。 ART 是和 Dalvik 共存的,用户可以在两者之间进行选择(感觉很奇怪,作为一个爱好者,我当时看到这个东西可以切换都是不晓得是什么玩意,用户可都是小白啊,没有必要共存的吧)。在Android 5.0的时候,ART 全面取代 Dalvik 成为 Android 虚拟机运行环境,至此。Dalvik 退出历史舞台,AOT 也成为唯一的编译模式。

二、ART 

AOT 和 JIT 的不同之处在于:JIT 是在运行时进行编译,是动态编译,并且每次运行程序的时候都需要对 odex 重新进行编译;而 AOT 是静态编译,应用在安装的时候会启动 dex2oat 通过静态编译的方式,来将所有的dex文件(包括Multidex)编译oat文件,编译完后的oat其实是一个标准的ELF文件,只是相对于普通的ELF文件多加了oat data section以及oat exec section这两个段而已。(这两个段里面主要保存了两种信息:Dex的文件信息以及类信息和Dex文件编译之后的机器码)。预编译成 ELF 文件,每次运行程序的时候不用重新编译,是真正意义上的本地应用。运行的文件格式也从odex转换成了oat格式。

其实在Android5.0的时候我们能够明显感觉手机好用很多就是因为这个原因,从根本上换掉了那种存在着无法解决弊端的虚拟机。在 Android 5.x 和 6.x 的机器上,系统每次 OTA 升级完成重启的时候都会有个应用优化的过程,这个过程就是刚才所说的 dex2oat 过程,这个过程比较耗时并且会占用额外的存储空间。

AOT 模式的预编译解决了应用启动和运行速度和耗资源(电等)问题的同时也带来了另外两个问题:

      1、应用安装和系统升级之后的应用优化比较耗时,并且会更耗时间。因为系统和apk都是越来越大的。

      2、优化后的文件会占用额外的存储空间

在经过了两个Android大版本的稳定后,在Android7.0又再次迎来了JIT的 回归。

JIT的回归,可不是把AOT模式给取代了,而是形成 了AOT/JIT 混合编译模式,这种模式至今仍在使用

应用在安装的时候 dex 不会被编译。

应用在运行时 dex 文件先通过解析器(Interpreter)后会被直接执行(这一步骤跟 Android 2.2 - Android 4.4之前的行为一致),与此同时,热点函数(Hot Code)会被识别并被 JIT 编译后存储在 jit code cache 中并生成 profile 文件以记录热点函数的信息。

手机进入 IDLE(空闲) 或者 Charging(充电) 状态的时候,系统会扫描 App 目录下的 profile 文件并执行 AOT 过程进行编译。

(Profile文件会在JIT运行的过程中生成:每个APP都会有自己的Profile文件,保存在App本身的Local Storage中。Profile会保存所调用的类以及函数的Index,通过profman工具进行分析生成)

个人理解:哪种模式擅长干什么就让他去干什么。

混合编译模式综合了 AOT 和 JIT 的各种优点,使得应用在安装速度加快的同时,运行速度、存储空间和耗电量等指标都得到了优化。

之前一直在说流畅,真的流畅在Android7.0上才感受到了些许。Android7.0系统也被用了相当长的一段时间。之后的Android8.0和Android9.0都是对各方面的优化,例如编译文件、编译器、GC。。

其中,值得一提的是华为的方舟编译器。

  • 首先会判断该设备支不支持方舟编译器,如果支持,则从应用商店下发方舟版本的包
  • 方舟编译器会把dex文件通过自己的IR翻译方舟格式的机器码,据资料说也是一个ELF文件,但是会增加一些段,猜测是Dex中类信息相关的段
  • 通过这种方式,来消除Java与JNI之间的通信的损耗,以及提升运行时的效率
  • 在方舟内部,还重新完善了GC算法,使得GC的频率大大降低,减少应用卡顿的现象
  • 目前方舟只支持64位的So,并且对于加壳的So会出现一些问题。

方舟编译器适配的应用,下载手机上都是方舟版本的包,特制的包用方舟编译器编译效率大大提升,之后直接执行就可以了,直接略过了在ART虚拟机上预编译的过程。这样的结果是很完美的,但是却也没办法跳过一个弊端。那就是生态。还是不管是安卓还是iOS,这么多年的时间沉淀中,他们的生态系统早就达到了一个非常完善的地步。安卓和iOS应用已经多达上千万,而方舟适配应用的数量还非常有限。

谷歌宣布将停止对华为提供安卓系统更新之后,华为曝光了自主研发的鸿蒙操作系统。当时网友各种力挺。不过后来,华为董事长梁华在谈及鸿蒙系统时称,鸿蒙系统是为物联网开发的,用于自动驾驶、远程医疗等低时延场景。鸿蒙系统是不是两手准备我们不得而知。但是,一个操作系统最重要的就是它的生态环境。纵观华为现在的整个格局,目的非常明确,用方舟编译器来扩大自己的用户群体。当用户的基数足够庞大时,可以随时随地建立一个完善的生态系统。如果在未来某一天,Android全面限制华为的使用之后,在这危机关头鸿蒙系统还是很有可能扛起国产手机的一面大旗。哪怕不是鸿蒙,我们也需要这样一个生态不是吗?

最初,突然去了解Android中的虚拟机,一个是想要明白到底Android中的虚拟机和JVM是不是一回事,还有就是想要明白华为发布方舟编译器到底快到了哪里。

上述相关资料均来自网络,侵权必删。

12-29 08:42