JIT(准时制)即时编译器是JVM运行时的重要部分,它使用JIT编译器将字节码编译成原生机器代码,从而提高了程序的执行效率。
在Java编程中,javac将程序源代码编译成java字节码(class文件)。这种代码格式不能直接在操作系统中运行,需要依靠不同平台的JVM通过解释器将字节码逐条翻译成相应的机器指令进行执行。由于这种执行方式比直接运行二进制机器码的速度要慢,所以引入了JIT技术来提高运行速度。
大部分日常开发中使用的JVM都是SUN公司的HotSpot虚拟机,所以接下来的解释都是基于HotSpot虚拟机进行的。
C1编译器在编译过程中不会应用过于激进的优化技术,只会对字节码进行部分优化,如方法内联、常量传播等。C1的编译速度较快,适合用于需要快速启动的项目。而C2编译器则会进行更深入的优化,包括无用代码消除、循环展开、消除公共字表达式等,虽然编译时间较长,但编译出的方法运行速度较快,适用于需要快速响应的服务类项目。
逃逸分析和栈上分配是JIT编译过程中的重要优化手段。逃逸分析可以确定对象的动态范围,如果对象没有逃逸,则可以在栈上进行分配,避免堆上分配带来的GC压力。栈上分配则是指java对象通常在堆上分配,如果一个对象经过逃逸分析后确定只被当前线程访问,那么该对象可以直接在栈上分配,随着栈帧的弹出被销毁,无需GC介入。
关于JIT的编译模式,JDK7之前需要开发人员手动选择开启C1或C2。但在JDK7及以后,JVM引入了分层编译模式的概念,综合了C1的高启动性能和C2的高峰值性能。这种模式下,一个方先被解释执行,然后可能被C1或C2编译。如果编译对象的复杂性适中,虚拟机可能会直接由C1编译并不插入profiling代码。而热点代码的探测则是通过方法调用计数器和回边计数器来实现的。