JITWatch: 优化JIT提高性能

HotSpot JVM 可以通过多种方式输出有关 JIT 优化决策的信息: 

  • PrintCompilation提供有关编译和内联的基本信息。
  • LogCompilation生成详细的 XML 格式,还描述分支预测、逃逸分析、内在函数、锁省略、代码缓存布局等。
  • PrintAssembly使用反汇编插件来输出 JIT 编译器在优化 Java 方法时生成的实际特定于平台的本机代码。

对于重要的程序来说,这些日志文件都不是特别容易阅读,因此我构建了一个名为 JITWatch 的可视化工具。

JITWatch 了解LogCompilation和PrintAssembly文件格式并对其进行解析,以生成用户友好的表示形式,展示程序在 JVM 上执行时所发生的情况。 它使用图表、表格、排行榜、直方图和其他视觉辅助工具来使故事更容易理解。

JITWatch 现已推出 10 周年,并且每月在 GitHub 上的克隆次数仍超过 1,000 次。我Oracle 内部的 JVM 团队仍在使用它。

如果你想专注于 Java 性能,那么JITWatch作者有几条建议:

  1. 了解完整执行堆栈的工作原理。了解您正在编写的漂亮的高级 Java 被编译成一个简单、可移植、基于堆栈的指令集(称为字节码),该指令集在解释器中开始执行,并依赖 JVM 分析和选择性 JIT 优化方法并循环到本机代码中以提高性能。
  2. 了解如何测量以及测量什么。刷新您对统计学关键概念的了解。下载Java Microbenchmark Harness (JMH),运行示例并尝试了解他们所教授的内容。
  3. 接受这样的事实:你对改进的直觉常常是错误的!源代码和 CPU 上执行的内容之间发生了很多事情,因此请使用可用的工具来尝试理解它。

背景
JVM 会构建正在运行的字节码的配置文件,并通过计算方法调用和循环后沿来查找频繁执行的“热点”(HotSpot JVM 的名称由此而来)。当这些计数器超过阈值时,方法(或循环)将排队等待编译。

JIT 编译器(HotSpot 包含两种编译器;一种简单,一种高级)从编译队列中获取方法,并使用收集的配置文件将字节码转换为优化的本机代码。

HotSpot JIT 优化包括方法调用去虚拟化、方法内联、死代码消除、公共子表达式消除、分支预测、锁粗化和锁省略、转义分析等等。本机代码存储在 JVM 的一个称为代码缓存的特殊内存区域中,对该方法的进一步调用将执行优化的本机代码,而不是解释后的字节码。

JIT 能够通过在称为“不常见陷阱”的本机代码中插入检查来进行推测性优化(假设它所观察到的行为将继续为真)。如果触发陷阱,则推测性假设将失效,并且 JVM 可以“取消优化”并恢复执行解释后的字节码,其中它将开始构建新的配置文件以允许稍后再次尝试和优化。