华为鸿蒙系统HarmonyOS学习之十四:方舟编译器
方舟编译器是华为自研的一个支持多种编程语言,多种芯片平台的联合编译编程平台,而经过方舟编译器编译适配后的APP,运行效率会大大提高,拥有更为流畅的体验,足以匹配IOS应用程序APP,华为方舟编译器所拥有的全新的应用编译和运行机制,能够从动态编译变为静态编译,直接将高级语言直接编译成机器码,彻底消除了虚拟机动态编译的额外开销,实现了开发和运行效率的兼容并举,所以方舟编译器也成为了华为鸿蒙OS系统发展中非常重要的一环。
方舟编译器是基于GCC开发的交叉编译器套件,它包括了C、C++、Fortran的前端,也包括了这些语言的库(如libstdc++、libgcc等)。HCC运行在X86 linux架构服务器上,生成的二进制运行在Aarch64架构服务器上。
要想说明方舟编译器的原理,必须首先明确机器码、汇编器、编译器、解释器等基本概念,以及常用的程序的运行模式,才能很好的理解编译器的运行原理。
(一)机器码、汇编器、编译器、解释器的概念
- 机器码
不论是低级语言,如汇编,还是如今广泛使用的各种高级语言,Java,C++ 等,对于 CPU 来说,它能认识的只有二进制的机器码。当然,机器码对开发人员来说,是天书。那么编写的代码来说,应该如何驱动 CPU 运行编写的程序呢?这个时候,在代码和CPU之间就需要一个翻译,将代码翻译成机器码给 CPU,它就知道该如何执行了。面对不同的终端,翻译内容也不一样,一个只知道 x86 指令集的去翻译 arm 的,肯定翻译不出来。肯定需要通过汇编器、编译器或者解释器等翻译工具,实现这种翻译。
- 汇编器
将汇编代码直接翻译成机器码。由于汇编代码一般和机器码都是一一对应的,所以它的速度非常快。但是汇编语言,可读性很差, 用来开发和编写大型程序对于普通开发者基本是不现实的。
- 编译器
编译器将我们平常开发用的高级语言,例如 Java/C++ 等,翻译成机器码供 CPU 使用。这种编译很慢,但是执行起来会很快。
- 解释器
程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。这种运行方式就慢了很多。 典型的解释型语言,php/js/python 等。
(二)java虚拟机的代码执行方式
Java 程序的执行依赖于 Java 虚拟机(JVM),JVM 能直接识别的叫做字节码。Java 代码经过编译会生成 Class 文件,即字节码文件,再交由 JVM 处理。而 JVM 又是怎么执行 Class 文件的呢?这里以 HotSpot 为例,Class 文件被虚拟机加载后会存放在方法区,实际运行时,虚拟机会执行方法区中的代码。
将字节码翻译成机器码的工作自然就由 JVM 来承担了。在 HotSpot 中,有几种翻译形式。
- 解释执行
逐条将字节码翻译成机器码并执行
- 即时编译(Just-in-time ,JIT)
将一个方法中包含的所有字节码编译成机器码后再执行。
前者的优势在于无需等待编译,而后者的优势在于实际运行速度更快。HotSpot 默认采用混合模式,综合了解释执行和即时编译两 者的优点。它会先解释执行字节码,而后将其中反复执行的热点代码,以方法为单位进行即时编译。
(三)andriod的执行方式的变革历程
开发 Android 目前用的最多的还是 Java,即使不是 Java,也是 JVM 语言。Android 工程中的 java 源文件经过编译也是生成 Class 文件,最后被打包成 DEX 字节码文件,负责将 DEX 字节码翻译成机器码的是 Dalvik 或者 Art。
在 Android 5.0 之前,还是 Dalvik 的天下。Dalvik 是解释执行加上 JIT,每次app运行的时候,它动态的将一部分 Dalvik 字节码 解释为机器码。随着 App 的运行,更多的字节码被编译和缓存。因为 JIT 只编译了一部分代码,它具有更小的内存占用和更少的设备物理空间占用。但是,边解释边执行,效率低下,这也是后来 Dalvik 遭到抛弃的原因。
从 Android 4.4 开始,Android 引入了 Art,到 Android 5.0,Art 正式代替了 Dalvik。Art 使用的是 AOT(Ahead of Time)的编译方式,即在应用的安装过程中,就将所有的 Dex 字节码翻译成机器码存储在设备空间中,完全抛弃了 JIT,带来的好处是显而易见的。
- Apps 运行的更快,因为 DEX 字节码的解释在安装过程中已经完成,直接运行机器码 减少了应用的启动时间,因为本地代码可以直接执行。 节省电量消耗,不需要再去一行一行的解释字节码。 增强了垃圾回收。 增强了开发者工具。
事实上,这种完全基于 AOT 的模式也已经被 Android 抛弃了。如果你用过 5.0 或者 6.0 的安卓机,你一定不会忘记安装应用带来的漫长等待。由于需要在安装期间翻译字节码,所以安装过程会很长,尤其对 一些大型应用来说。另外,安装过程中翻译出来的机器码也占用了更大的机身存储空间。
Android 7.0,Android 又加入了 JIT,一个具备代码分析功能的即时 (JIT) 编译器。事实上,根据二八定律,经常运行的热点代码可能只占 20%,甚至更少,我们没有必要通过 AOT 提前将所有字节码都翻译成机器码。安装过程中放弃 AOT,加快安装速度,所以初次使用时得解释执行。当你在使用应用时,JIT 就开始分析代码了,在合适的时候将字节码翻译成机器码,在 Android 应用运行时持续提高其性能。另外,设备空闲的时候,AOT 就发挥作用了,它会将热点代码翻译成机器码并保存下来,进一步提高运行效率。这么看下来,现在的 Android 是 解释执行 、JIT、AOT 同时存在的。下面这张官网的图片很好的说明了Art 下的 JIT 架构.
关于解释器,高版本中的 Android 实现也不再那么孱弱了,根据官网相关介绍:
通过引入 Mterp(一种解释器,具有以汇编语言编写的核心提取/解码/解释机制),Android 7.0 版本中的解释器性能得以显著提升。Mterp 模仿了快速 Dalvik 解释器,并支持 arm、arm64、x86、x86_64、mips 和 mips64。对于计算代码而言,ART 的 Mterp 大致相当于 Dalvik 的快速解释器。 不过,有时候,它的速度可能会显著变慢,甚至急剧变慢:
- 调用性能。 字符串操作和 Dalvik 中其他被视为内嵌函数的高频用户方法。 堆栈内存使用量较高。
Android 8.0 解决了这些问题。
说了这么多,无非是安装速度,空间占用,运行速度的平衡,目前 Android 应该已经做得很好了,但仍然存在不少诟病。
(四)方舟编译器采用的技术
方舟编译器,安卓性能革命突破:方舟编译器是业界首个多语言联合优化的编译器,开发者在开发环境中可以一次性将多语言统一编译为一套机器码,运行时无需产生跨语言带来的额外消耗,并可以进行跨语言的联合优化,提升运行效率。安卓自身的编译技术在不断的发展,但始终需要在运行中依赖虚拟机来进行动态编译和解释执行,对系统资源消耗较大。而方舟编译器在开发环境中就可以完成全部代码的编译,手机安装应用程序后无需依赖虚拟机资源,即可全速运行程序,带来效率上的极大提升。举一个例子:EMUI 9.1仅仅对系统组件System Server应用了华为方舟编译器后,就带来了系统操作流畅度提升24%,系统响应性能提升44%的收益
方舟编译器,高效的回收机制:内存管理是程序开发与运行时需要重点考虑的部分,也和系统流畅度息息相关。安卓在内存回收上采用集中回收机制,发声全局回收时更需要暂停应用,这也是随机卡顿的根因之一。而方舟编译器提供了更高效的内存回收机制,回收时无需暂停应用,随时用随时回收,大大提高运行速度。
方舟编译器,应用级编译优化:代码优化是编译器最为核心的功能,也是评判一个编译器优劣最重要的标准。当前由于安卓应用使用了虚拟机机制,难以面向不同应用对虚拟机进行针对性的灵活优化。安卓ART的AoT和JIT动态编译因为是运行在手机上,受资源所限,因而只能使用简单的优化算法。而方舟编译器由于是在应用开发阶段进行编译,所以可以允许不同应用灵活采用不同的编译优化方案,而且因为在开发环境编译不会受到手机性能的限制,可以使用更多先进的优化算法,从而使得每个应用的性能达到最佳。
超级文件系统,读取更顺畅: 在业界规模商用F2FS文件系统,替代了传统的EXT4文件系统,令用户分区的文件读写流畅度提升20%;而超级文件系统(EROFS)采用专利压缩算法加持,使得系统分区随机读性能平均提升20%,并减少14%系统空间占用。
超级文件系统,安全又高效:超级文件系统天然只读设计,系统分区不可被三方改写,更为安全。
HiAI生态开放共享,更多智能体验:HiAI开放能力不断增强,支持算子数量增加至147算子,API上线数量增加33个API,接入原子化服务超3200项。已经有很多合作伙伴利用HiAI开放平台给消费者提供了很多创新体验,比如storysign利用HiAI的API能力帮助残障人士进行无障碍的阅读。通过开放的全球生态系统,以及1400+生态合作伙伴和560000+的开发者,用户将会获得更多更丰富的智慧场景体验
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/291193.html