博客
关于我
Java即时编译器原理解析及实践详解!你的Java基本功真的扎实吗?
阅读量:794 次
发布时间:2023-01-28

本文共 1926 字,大约阅读时间需要 6 分钟。

JVM 即时编译机制解析与实践

Java 作为一门解释型语言,凭借其“一次编译,处处运行”的特点,凭借着设计上的巧妙之处,在性能与便捷性之间找到了平衡。然而,这种语言的性能通常不如传统的编译型语言(如 C++)。为了弥补这一不足,Java 引入了即时(Just In Time,JIT)编译器,使得运行时环境能够在程序运行过程中对热点代码进行优化,提升性能。

JVM 执行过程解析

Java 的执行过程主要分为两个阶段。首先,javac 将源码编译成通用的中间形式——字节码。在此过程中,编译器会进行词法分析、语法分析和语义分析。这个阶段称为前端编译。随后,不需要再次编译字节码,直接交给解释器逐条解释执行。在解释执行过程中,虚拟机(JVM)同时对程序运行的信息进行收集,在这些信息的基础上,编译器会逐步发挥作用,进行后端编译,将字节码优化为机器码,但并非所有代码都会被编译,只有被 JVM 认定为热点代码才会被优化。

JVM 中的编译器

JVM 集成两种编译器:Client Compiler(C1)Server Compiler(C2)。两者在性能和启动速度之间寻求平衡。

Client Compiler(C1)

C1 编译器的目标是为快速启动和局部优化做准备。其主要功能包括:

  • 局部简单可靠的优化,如方法内联和常量传播。
  • 将字节码转换为高级中间表示(HIR),然后进一步转化为低级中间表示(LIR)。
  • 进行寄存器分配和窥孔优化,生成最终的机器码。
  • Server Compiler(C2)

    C2 编译器主要关注全局优化,性能优于 C1。其默认的全局优化手段包括:

  • 使用一种控制流与数据流结合的图数据结构——Ideal Graph,构建程序依赖关系。
  • 结合程序运行信息进行着级优化。
  • 最后生成机器码。
  • 分层编译

    Java 7 以 Slaurar 展开的分层编译概念结合了 C1 和 C2 的优势。通过对程序运行状态的分层,JVM 可以在保证性能的同时,优化启动速度。分为五个层次:

  • 解释执行
  • 不带 profiling 的 C1 编译
  • 仅带方法调用次数的 C1 编译
  • 带 profiling 的 C1 编译
  • 使用 C2 编译
  • 即时编译的触发

    即时编译的触发条件主要基于方法调用次数和循环回边次数。当调用次数或回边次数超过阈值时,JVM 会触发即时编译。默认阈值由参数 -XX: CompileThreshold 控制。

    编译优化

    即时编译器的优化主要包括中间表达形式优化、方法内联以及全局优化。特别是在 C2 编译器中,采用 Ideal Graph 进行全局优化,使得编译效率显著提升。

    中间表达形式

    现代编译器普遍使用静态单赋值(SSA)中间表达形式。SSA IR 在程序优化中具有显著优势,能够简化死代码删除、全局值编号等优化操作。

    方法内联

    方法内联是 JIT 的重要优化手段。通过将目标方法的代码与调用者代码合并,减少方法调用开销,显著提升性能。

    全局优化

    C2 编译器通过 Ideal Graph 构建程序依赖关系,收集程序运行信息,进行全局优化。此外,结合 Global Value Numbering(GVN)消除公共子表达式,将优化效果最大化。

    实践经验

    编译参数优化

    • -XX:+TieredCompilation:开启分层编译(默认 JDK 8 后启用)。
    • -XX:CICompilerCount:设置编译线程数,默认为 2(C1:C2=1:2)。
    • -XX:TierXBackEdgeThreshold:OSR 编译阈值。
    • -XX:TierXMinInvocationThreshold:方法调用频率阈值。
    • -XX:TierXCompileThreshold:编译阈值。

    使用 JIT 分析工具

    通过 JITwatch 等工具分析编译日志,了解 JIT 的编译状态,发现热点代码和潜在优化点。

    测试 Graal 编译器

    Graal 编译器自 JDK 9 起开始支持,能够显著提升性能。需注意其与 G1垃圾回收器的兼容性,并在启动添加 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler 参数。

    总结

    JVM 的即时编译机制为 Java 提供了性能优化的手段,通过 C1 和 C2 编译器的结合与分层编译,尽可能在性能与启动效率之间取得平衡. Graal 编译器的引入为 Java 的性能提升开辟了新方向,但仍需注意其在启动阶段的性能挑战。对于实际应用,合理使用编译器参数,结合 Graal 编译器,能够显著优化 Java 服务性能,这也是技术团队在性能优化中的重要方向。

    转载地址:http://onryk.baihongyu.com/

    你可能感兴趣的文章
    Docker+Jenkins+GIT CICD持续化集成实战
    查看>>
    Dockerfile 指令详解
    查看>>
    Docker安装MongoDB(附Docker虚拟机环境与MongoDB客户端连接工具)
    查看>>
    DRBL+Clonezilla全自动批量安装操作系统
    查看>>
    Dva员工增删改查Demo实现-优化
    查看>>
    EasyUi的使用与代码编写(一)
    查看>>
    ECSHOP实现收货国家省市由选择下拉菜单改为手动
    查看>>
    EdgeX Foundry:开启边缘计算新时代
    查看>>
    Edge浏览器打开控制台后程序总是停止进入debug模式关闭教程【八仙过海之又一过海方案】
    查看>>
    Educational Codeforces Round 28
    查看>>
    ed编辑器--适用于shell脚本内编辑文件的最最简单编辑器
    查看>>
    EF 资料
    查看>>
    Effective Modern C++:02auto
    查看>>
    efficientnet最合适的尺寸和最后一层的层数
    查看>>
    Ehcache Java开源缓存框架
    查看>>
    EJB学习笔记六(EJB中的拦截器)
    查看>>
    el-form表单重置后输入失效
    查看>>
    el-select下拉框修改背景色
    查看>>
    el-table select事件判断当前项是否勾选
    查看>>
    Elasticsearch & Kibana & Filebeat开启SSL通信
    查看>>