Android ART虚拟机执行引擎详情
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中。