AOT编译器和JIT编译器在ART中的区别

13

在 Marshmallow 中,ART 添加了 AOT 编译器。从 Android N 开始,除了 AOT,还添加了 JIT 编译器。

AOT 编译器的具体工作/特点以及 JIT 编译器的工作/特点是什么?

3个回答

30

在Android中,Java类被转换为DEX字节码。通过ART或Dalvik运行时,将DEX字节码格式翻译成本地机器代码。

Dalvik是一种基于JIT(即时编译)的引擎。使用Dalvik有缺点,因此从Android 4.4(KitKat)开始引入了ART作为运行时,并且从Android 5.0(Lollipop)开始完全替代了Dalvik。 Android 7.0添加了一个具有代码分析功能的JIT编译器到Android运行时(ART),它不断提高Android应用程序的性能。

(Dalvik使用JIT(即时编译),而ART使用AOT(预先编译)。)

即时编译(JIT):

使用Dalvik JIT编译器,每次运行应用程序时,动态将一部分Dalvik字节码转换为机器代码。随着执行的进行,将编译并缓存更多的字节码。由于JIT只编译部分代码,因此其内存占用较小,可以在设备上使用较少的物理空间。

预先编译(AOT):

ART配备了一个预先编译器。在应用程序的安装阶段,它会静态地将DEX字节码转换为机器代码并存储在设备的存储器中。这是一个在应用安装时发生的一次性事件。

Android N包括混合运行时:

不会在安装期间进行任何编译,并且应用程序可以立即启动,字节码被解释执行。ART中有一个新的、更快的解释器,并且它还配备了一个新的JIT,但JIT信息不会保存。相反,在执行过程中对代码进行分析,并保存所得到的数据。

ART的好处:

  • 在安装期间完成DEX字节码翻译,因此应用程序运行更快。
  • 直接执行本地代码,减少应用程序启动时间。
  • 节省电池电量,因为无需逐行解释字节码。
  • 改进的垃圾收集器。
  • ART 的缺点:

    • 由于在安装过程中需要将 DEX 字节码转换为机器码,因此应用程序安装需要更长的时间。

    • 由于安装时生成本地机器码存储在内部存储器中,所以需要更多的内部存储空间。


    10

    编译器需要两样东西来生成高效的代码:信息和资源。

    JIT编译器比AOT编译器拥有更多的信息。静态分析在一般情况下是不可能的(你想知道程序中几乎所有有趣的事情都可以归结为停机问题或Rice定理),即使在特殊情况下也很困难。JIT编译器没有这个问题:它们不必静态地分析程序,而是可以在运行时动态观察它。

    此外,JIT编译器有一些AOT编译器所没有的技术,最重要的一项是去优化。现在,你可能会认为,为什么去优化对性能很重要?如果你可以去优化,那么你就可以过度地进行实际上是无效的优化(例如内联可能是多态的方法调用),如果发现错误,那么你可以反悔到未内联的状态(例如)。

    然而,还有一个资源的问题:AOT编译器可以花费任意时间,并使用任意数量的内存。JIT编译器必须从用户现在想要使用的程序中窃取资源。

    通常情况下,这不是问题。我们今天的计算机是如此强大,以至于JIT的可用资源总是足够的。特别是当大量新代码一次性引入系统时,JIT会使用最多的资源,这通常发生在程序启动时,或者当程序从一个阶段过渡到另一个阶段(例如,从解析配置文件到设置对象图,或者从完成配置到开始实际工作),此时程序本身通常还没有使用太多资源(尤其是在程序启动期间)。Azul JCA是一个很好的例子。在其最大配置中,它有864个核心和768 GiByte RAM(请注意,它们已经很长时间没有出售了,所以实际上是几年前的技术)。根据Azul的测量,当JIT非常努力地工作时,它可能使用50个核心。仍然有超过800个核心可供程序、系统和GC使用。

    然而,您典型的Android设备并没有1000个核心和1 TiB内存。当用户启动WhatsApp时,他想立即写一条消息。他不想等待500毫秒,让JIT热身。现在就要。

    这正是AOT在这里具有吸引力的原因。还要注意,JIT编译不仅会从正在运行的程序中窃取资源,还需要电池电力,并且每次运行程序时都需要电力,而AOT编译器只需要在安装应用程序时花费一次电力预算。

    您甚至可以将编译推迟到应用商店或开发人员,就像苹果公司所做的那样,但苹果公司具有更受限制的可能目标平台集合的优势,因此对于Android来说,在设备上进行AOT编译似乎是一个合理的折衷方案。


    你的回答很好,但是太长了。 - Det
    很好的答案。即使更长,我仍然喜欢阅读它。我在想JIT可用的额外信息是否真的对性能提升有多大帮助。 - Trilarion
    @farhan 为什么在构建apk时,Android不直接编译.oat或本地二进制文件,以便在安装应用程序后无需进行编译? - Siva

    3

    JIT和AOT的区别

    .java -> .class -> .dex(by DX, D8) -> machine byte code
    

    即时编译(JIT) - Dalvik(基于寄存器) - 在执行之前生成机器字节码。它的内存占用更小,但CPU使用量更大(滞后),有时性、电池寿命短。

    预先编译(AOT) - Android Runtime(ART) - 在安装期间生成机器字节码。在API 19中引入,并在API 21中成为默认设置。首次启动需要更长时间。 ART优化了内存分配和垃圾回收器(GC)-只进行一次迭代。

    从API 24开始,ART采用混合方法,结合了AOT和JIT [ClassLoader]


    1
    你的意思是在API 21中成为了默认值吗? - Anwar

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接