欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android ART虚拟机执行引擎详情

程序员文章站 2022-06-30 20:57:10
Just-in-time compilation是一种动态编译,是在程序运行过程中才执行编译工作。相对于ART的核心技术ahead-of-time,JIT有几个有点:比AOT更节省...

Just-in-time compilation是一种动态编译,是在程序运行过程中才执行编译工作。相对于ART的核心技术ahead-of-time,JIT有几个有点:比AOT更节省存储空间;不需要在每次安装,或者系统升级、应用升级后都做AOT优化。

因为不需要在程序安装时执行AOT预编译,所以不会出现漫长的安装等待,不会影响程序的启动速度。

JIT的编译过程是在独立的线程中完成的,并且只编译有必要的函数。

AOT的编译有两个主要的执行时机:一是ROM系统编译时,一是第三方应用程序安装时。

1),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中选择最合适的执行方式了。

JIT对应的源码实现在art/runtime/jit/,是在runtime的start过程中启动的。

art/runtime/Runtime.cc

bool Runtime::Start() {
  // Create the JIT either if we have to use JIT compilation or save profiling info.
  // TODO(calin): We use the JIT class as a proxy for JIT compilation and for
  // recoding profiles. Maybe we should consider changing the name to be more clear it's
  // not only about compiling. b/28295073.
  if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
    std::string error_msg;
    if (!IsZygote()) {
    // If we are the zygote then we need to wait until after forking to create the code cache
    // due to SELinux restrictions on r/w/x memory regions.
      CreateJit();
    } else if (jit_options_->UseJitCompilation()) {
      if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
        // Try to load compiler pre zygote to reduce PSS. b/27744947
        LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
      }
    }
  }
}

其中是否使用JIT,由jit_options_->UseJitCompilation()来判断。

然后调用CreateJit生成JIT实例,具体代码是调用Jit::Create,实现在art/runtime/jit/jit.cc,

void Runtime::CreateJit() {
  jit_.reset(jit::Jit::Create(jit_options_.get(), &error_msg));
  if (jit_.get() == nullptr) {
    LOG(WARNING) << "Failed to create JIT " << error_msg;
  }
}

JIT模块完成的主要任务:

监测程序运行,获取需要翻译的函数信息;

通过profileSaver将获取的信息存入文件中;

有jit_compile_method(art/rumtime/jit/jit_compiler.cc)实时翻译运行过程中的热点函数,保存到jitCodeCache中。