Android ART虚拟机执行引擎-JIT(九)

本文详细介绍了Just-in-Time(JIT)编译机制的工作原理及其在Android平台上的实现细节。JIT作为一种动态编译技术,在程序运行时进行编译,能够显著减少存储空间占用,避免长时间的安装等待,提升程序启动速度。文章还阐述了JIT与Ahead-of-Time(AOT)编译的区别,以及Profile Guided Compilation如何通过收集热点函数信息来优化程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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中。

<think>我们首先需要明确两个概念:什么是进程虚拟机?什么是JIT编译器? 进程虚拟机(Process Virtual Machine)是指提供一个与物理硬件无关的运行环境,允许程序在独立于底层操作系统和硬件的环境中运行。它通常用于支持跨平台执行,例如JVM和CLR就是典型的进程虚拟机JIT编译器(Just-In-Time Compiler)是指在程序运行时将中间代码(如字节码)动态编译成本地机器码的技术,以提高执行效率。 现在,问题分为两部分: 1. LLVM是否具备JIT编译功能? 2. LLVM是否可以归类为集成JIT的进程虚拟机? 根据引用[4]:LLVM是一个编译器基础设施,最初作为编译后端使用(替代GCC)。它包含了一系列模块化的编译器组件和工具链,支持代码优化和生成多种目标平台的机器码。 关于LLVM的JIT功能: LLVM确实提供了JIT编译功能。LLVM的核心是中间表示(IR),它可以被优化,并且可以通过JIT引擎在运行时编译成机器码执行。LLVM的JIT编译器(如MCJIT和ORCJIT)是其重要组成部分,允许动态编译和执行IR代码。 但是,LLVM本身并不是一个完整的进程虚拟机。它是一个编译器框架,可以被用来构建虚拟机(如JVM、CLR)中的JIT编译器部分,但LLVM本身并不提供虚拟机所需的其他功能,例如: - 内存管理(垃圾回收) - 线程调度 - 异常处理 - 类加载(对于Java虚拟机)或程序集加载(对于CLR) - 字节码解释器(虽然LLVM可以JIT编译,但通常不包含解释器,除非特别实现) 因此,我们可以这样回答: 1. **LLVM具备JIT编译功能**:LLVM提供了强大的JIT编译框架,可以将LLVM IR动态编译为机器码并执行。例如,使用LLVM的JIT库,我们可以实现一个即时编译器,动态编译并执行代码[^4]。 2. **LLVM本身不是进程虚拟机**:尽管LLVM提供了JIT编译功能,但它并不直接等同于一个进程虚拟机。进程虚拟机需要提供完整的运行时环境(包括内存管理、线程管理、异常处理等),而LLVM仅专注于编译和优化。然而,LLVM可以被用作构建进程虚拟机中的JIT编译器组件。例如,一些虚拟机(如Android Runtime ART的AOT编译,以及某些JavaScript引擎)使用LLVM作为后端来生成机器码。 举例说明: - 引用[3]提到JavaScriptCore(JSC)引擎使用了多级JIT编译器,其中一种就是基于LLVM构建的(称为FTL JIT)。但JSC本身是一个完整的虚拟机(包含解释器、多级JIT、垃圾回收等),而LLVM只是其JIT编译器的一部分。 - 同样,引用[4]提到苹果用LLVM作为编译后端,但整个运行时环境(如Objective-C运行时)并不是由LLVM单独提供的。 结论: - LLVM是一个强大的编译器框架,它包含JIT编译功能,但本身不是一个集成JIT的进程虚拟机- 进程虚拟机(如JVM、CLR)通常会集成JIT编译器,而LLVM可以被用来实现这些JIT编译器。 因此,回答用户的问题:LLVM具备JIT编译功能,但不能被归类为集成JIT的进程虚拟机,因为它本身并不提供完整的虚拟机运行时环境。它更准确地说是一个用于构建编译器和相关工具(包括JIT)的框架。 最后,根据要求,生成相关问题。</think>### LLVM是否具备JIT功能并可归类为集成JIT的进程虚拟机? #### 1. **LLVM的JIT编译功能** **LLVM确实具备JIT编译能力**,这是其核心特性之一: - **JIT引擎实现**:通过`MCJIT`(多目标JIT)和`ORCJIT`(On-Request Compilation)等模块,LLVM可在运行时将中间表示(IR)动态编译为机器码[^4]。 - **工作流程**: ```mermaid graph LR A[源代码] --> B(LLVM前端生成IR) B --> C{执行模式} C -->|JIT模式| D[LLVM JIT编译为机器码] C -->|AOT模式| E[静态编译为二进制] ``` - **与纯编译器的区别**:传统编译器(如GCC)仅支持提前编译(AOT),而LLVM的模块化设计允许灵活切换AOT/JIT模式[^4]。 #### 2. **LLVM是否属于进程虚拟机?** **LLVM本身不是完整的进程虚拟机**,但可构建虚拟机核心组件: - **虚拟机的关键特征**: | 功能 | 进程虚拟机(如JVM) | LLVM | |---------------------|---------------------|--------------------| | 字节码执行环境 | ✓ (Java字节码) | ✗ (仅处理IR) | | 内存管理/GC | ✓ | ✗ (需额外实现) | | 线程调度 | ✓ | ✗ | | **JIT编译器** | ✓ | ✓ (作为核心组件) | - **定位差异**: - LLVM本质是**编译器基础设施**,提供IR优化和代码生成能力。 - 进程虚拟机(如JVM)是**完整运行时环境**,包含执行引擎、内存管理、安全沙箱等[^1][^4]。 - **实际应用**:LLVM常被用作虚拟机JIT后端,例如: - JavaScript引擎(如WebKit的FTL JIT)使用LLVM进行深度优化[^3]。 - Java虚拟机(GraalVM)用LLVM作为编译管道的一部分。 #### 3. **典型对比:LLVM vs JVM/CLR** ```mermaid graph TB subgraph JVM/CLR[进程虚拟机] A[字节码加载] --> B[JIT编译器] B --> C[机器码执行] D[GC内存管理] --> A E[线程管理] --> C end subgraph LLVM[编译器框架] F[源代码] --> G[生成IR] G --> H[JIT编译] H --> I[机器码执行] style H fill:#9f9,stroke:#333 end ``` - **关键区别**:LLVM的JIT仅负责代码生成(图中绿色部分),而JVM/CLR还包含完整的运行时管理(GC、线程等)[^1][^5]。 #### 4. **结论** 1. **JIT功能**:LLVM具备强大的JIT编译能力,可将IR动态编译为机器码[^4]。 2. **虚拟机归类**: - ❌ **不是独立进程虚拟机**:缺少字节码执行环境、内存管理等关键组件。 - ✅ **是虚拟机JIT引擎的构建基础**:常被集成到虚拟机中作为高性能JIT后端(如JavaScriptCore的LLVM FTL JIT)[^3][^4]。 > 简言之,LLVM是“可集成JIT的编译器框架”,而非完整的进程虚拟机。它像为虚拟机提供动力的引擎JIT核心),但需要配合其他模块才能构成完整的“汽车”(虚拟机)[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值