HotSpot JVM 提供了两种 JIT(即时编译)编译器:Client Compiler 和 Server Compiler。这两种编译器的设计目标和优化策略有所不同,主要是为了适应不同的应用场景,分别优化启动时间和运行性能。
1. Client Compiler(客户端编译器)
Client Compiler(通常称为 C1 编译器)是一个轻量级的编译器,旨在优化 启动时间 和 较低的硬件性能。它主要用于那些对启动速度要求较高,但长期性能要求相对较低的应用场景。
特点:
- 优化启动时间:Client Compiler 采用了更简单的优化策略,以加速应用的启动时间。它通过较少的编译优化和更快速的编译过程来确保应用尽早运行。
- 较低的优化级别:C1 编译器做的优化相对较少,因此编译速度较快,适用于一些启动要求高,但对最终性能没有过高要求的场景。
- 面向低端机器:C1 编译器通常适用于那些资源有限、硬件性能较差的环境(如低端桌面系统、嵌入式系统等)。
优化特点:
- 局部优化:比如方法内联、常量折叠等简单的优化。
- 较少的复杂优化:它不会进行一些复杂的优化(如循环展开、热点方法优化等),因为这些操作会增加编译时间。
适用场景:
- 用于桌面应用程序、轻量级的客户端应用程序或快速启动的开发环境。
2. Server Compiler(服务器编译器)
Server Compiler(通常称为 C2 编译器)是一个高级的、优化较多的编译器,旨在优化 长时间运行的服务器端应用程序,特别是那些对运行性能要求非常高的应用。C2 编译器的编译速度较慢,但它能产生高度优化的机器代码,从而提高最终的运行性能。
特点:
- 优化运行性能:Server Compiler 进行复杂的优化,通常需要较长的编译时间,但是生成的机器码执行效率非常高,适合长期运行的程序。
- 高度优化:它采用更复杂的优化技术,如 循环展开、全局数据流分析、方法内联、逃逸分析 等,使得生成的代码执行效率远高于 Client Compiler。
- 适用于高负载应用:C2 编译器更适合需要长时间运行和高性能的服务器应用,如大型 web 服务、数据库应用、大型企业应用等。
优化特点:
- 全局优化:比如方法内联、循环展开、逃逸分析等复杂的优化。
- 目标是最大化运行时性能,而不仅仅关注启动速度。
适用场景:
- 服务器端应用、高负载应用、大型的后端系统等,通常需要较长的启动时间但要求极高的运行效率。
3. Client Compiler 和 Server Compiler 的选择
在 JDK 8 中,JVM 会根据你的环境自动选择使用 Client Compiler 还是 Server Compiler:
- 默认情况下,如果你的机器是 桌面 或者启动时间非常重要,JVM 会选择 Client Compiler。
- 如果是 服务器环境 或者机器具有较强的计算能力,并且主要关注长时间运行时的性能,JVM 会选择 Server Compiler。
Java7引入了分层编译,使用-XX:+TieredCompilation参数开启,它综合了C1的启动性能优势和C2的峰值性能优势。
在Java8中默认开启了分层编译,在Java8中,无论是开启还是关闭了分层编译,-cilent和-server参数都是无效的了。当关闭分层编译的情况下,JVM会直接使用C2。
在我们电脑上使用 java -version命令 可以看到
mixed mode 混合模式
在上图我们还能看到,后面有mixed mode标注,这是什么意思?
它指的是 JVM 在执行时同时使用了 解释模式(Interpretation)和 JIT 编译模式(Just-In-Time Compilation)。
-
解释模式(Interpreter Mode):
- 初始阶段,JVM 会使用 解释器(Interpreter)逐行解释执行 Java 字节码。
- 这种方式启动较快,但性能较差,因为每条指令都需要逐步解释。
-
JIT 编译模式(Just-In-Time Compilation Mode):C1/C2编译器
- 在程序运行时,JVM 会使用 JIT 编译器,将热点代码(即经常执行的代码)编译成本地机器码,以提高性能。
- JIT 编译器在运行时动态地编译字节码,避免了反复解释,提高了执行速度。
-
这种方式的好处是:
- 快速启动:解释执行可以在程序启动时较快地开始执行。
- 性能优化:随着程序的执行,JVM 会识别出频繁执行的代码并用 JIT 编译器优化,提高性能。
欢迎大家积极讨论,及时指出不同观点,互相交流学习~
参考
深入理解java虚拟机(十三) Java 即时编译器JIT机制以及编译优化_java虚拟机即时编译器编译优化技术-优快云博客