酷勤网 – 程序员的那点事!

当前位置:首页 > 编程 > 移动开发 > 正文

继续谈谈下一代Android VM runtime: ART

浏览次数: 知乎专栏 2015年09月14日 字号:

最开始以为ART自己重新弄了一套bytecode和JIT,但前天浏览ART代码时没有发现和JIT(即时编译器)有关的部分,也没有看到OAT里自己定义bytecode,所以在上一篇blog里谈到ART时只提到dex=>oat的编译器是基于llvm构建,没有说起JIT。

后来VM专家@Hank看了代码以后直接表示说这是一个AOT,我才反应过来。所谓AOT (Ahead of Time)是指在运行以前就把中间代码静态编译成本地代码,而JIT (Just inTime)则是在运行时动态编译。我公司前几年的主力产品就是一款同时拥有AOT和JIT两套编译器的Java VM。

AOT和JIT比各有长处,这里不详细展开,只简单列举几个最主要的:

  • AOT的主要编译过程发生于开发用机,因此编译得慢一点没关系,可以充分的做各种耗时的优化;JIT在运行时动态编译,通常不能做太耗时的优化,否则影响启动和运行速度
    • 更具体一点,以Sun的JVM为例,JIT大体上划分为client和server两种模式。Client模式下VM是一边解释执行,一边识别热点区域进行JIT编译,以免明显影响启动速度;考虑到内存占用,也不会把所有Java字节码都编译成本地代码。Server模式下则会进行全面的JIT编译,因为server启动慢一点没关系,一旦跑起来就会运行很长时间,所以花一点点时间全面优化是值得的。
  • 因为受优化程度限制,JIT编译出来的本地代码体积通常比较大,5到10倍于bytecode都是正常的。AOT编译出来的本地代码体积更小。Android的JIT code cache也是内存占用的重要角色。
  • 因为是预编译好的机器代码,AOT产生的代码和加载执行过程和普通的本地代码没有太大分别。不过仍然需要运行时的GC支持。
  • 虽然AOT可以有更多的时间和空间做编译优化,但并不等于性能上就一定胜过JIT。JVM有不少东西只能在运行时动态决定是否可以采用编译优化(如识别可以inline的虚方法),以及运行时动态反优化(例如inline了一个虚方法,后来发现遇到新的派生类的实例,就需要取消原来的inline)。这些事情AOT就不容易做到。
  • AOT的编译器一般会分两个版本,一个在开发机上编译整个系统和预装应用,另一个是一个精简版,在设备上运行,负责编译连接新安装的应用。
  • AOT编译出来的代码仍然需要运行时的支持,特别是GC。

如果ART确实是用AOT compiler替换JIT,性能先不谈,Android的内存占用应该会因此获益。现在dex代码经过 dex => optimized dex => JIT cache这个过程,内存中需要同时容纳odex和JIT cache两份代码;换成ART以后,就变成dex => oat,内存里只放oat就可以。不过考虑到ART的解释器代码里有提到deoptimization,也有可能在特定情况下还需要load dex代码解释执行。重要的是oat应该是可以直接mmap执行的代码(其实就是一个真·ELF格式的文件),加载/换页重加载的速度都会比从odex动态编译来得快。

不是VM专家,有什么地方说得不清楚/不正确的欢迎指正 :)

无觅相关文章插件,快速提升流量