JitWatch

最近工作中需要验证某种写法在 jit 下的行为,捣鼓了一下 jit-watch,现在记录下相关步骤。

前置准备

在启动参数中增加 java -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods -Xcomp 即可输出 jit 编译结果到控制台,但是这样输出的是二进制机器码,需要安装 hsdis 动态库将其转换成汇编。hsdis 的下载地址

下载完成后将对应的文件放在如下位置:

/lib/server/hsdis-.
/lib/hsdis-.

这个时候再次运行程序,输出到控制台的就是汇编语句了。为了方便查看,一般还需要重定向到文件中,过程略显繁琐,jitwatch 登场。

JitWatch

JitWatch github 地址:JitWatchmvn clean package 编译,在路径 jitwatch/scripts 执行 bash launchUI.sh 即可运行。

如遇到菜单文字乱码,在启动脚本里增加 -Duser.language=en 指定英文。

javafx 运行环境

另外,如果使用的是高版本的 JDK,javafx 已经分离开,而 jitwatch 依赖 javafx,需要按如下步骤配置 javafx 运行环境:

  • 下载 javafx sdk 并解压 javafx

  • 配置 launchUI.sh 如下:

    • 导出 javafx 的地址变量:javafx_path=/home/senninha/soft/jdk/javafx-sdk-22.0.2/lib

    • 启动参数增加 --module-path $javafx_path --add-modules javafx.controls

      1
      2
      3
      javafx_path=/home/senninha/soft/jdk/javafx-sdk-22.0.2/lib

      "$JAVA_HOME/bin/java" --module-path $javafx_path --add-modules javafx.controls -Duser.language=en -cp "$CLASSPATH" "$@" org.adoptopenjdk.jitwatch.launch.LaunchUI

启动:

image-20240804124847318沙箱

JitWatch 有沙箱模式,可以在配置好的环境中运行代码并给出源代码、字节码、Jit 的汇编代码对比。现在先配置一下沙箱环境,将 Java 运行时配置成已经安装了 hsdis.so 文件的版本。

jit_watch_sandbox_config

运行示例代码

直接在沙箱中 editor 新建一个文件,run 运行以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.ArrayList;
import java.util.List;

/**
* @author senninha
*/
public class TestJitOutput {
public static void main(String[] args) {
int count = 1000000;
List<Integer> lst = new ArrayList<>();
while (count-- > 0) {
lst.add(new TestJitInstance().calc(count));
}
System.out.println(lst);
}

private static class TestJitInstance {
public int calc(int i) {
return i * 10;
}
}
}

可以直接看到源代码、字节码、jit汇编代码:

sandbox_test

可以看到,示例代码中的 new TestJitInstance() 在 jit 后被消除,calc 中的逻辑被内联完全展开。

对于最右边的汇编,可以参考哈佛大学的 cs61,非常浅显易懂。