likes
comments
collection
share

JITWatch很折腾?有这篇文章在可以放心

作者站长头像
站长
· 阅读数 12

简单介绍

什么是JITWatch?

什么是JITWatch?

大多数情况下,通过诸如javap等反编译工具来查看源码的字节码已经能够满足我们的日常需求。

但是不排除在有些特定场景下,我们需要通过反汇编来查看相应的汇编指令。

JITWatch——JIT编译日志分析工具 提供了可视化界面帮助我们直观的查询汇编代码。

字节码指令和汇编指令

字节码指令和汇编指令区别

Java我们知道是一种跨平台语言,那么Java如何实现平台无关性呢?这就需要我们了解JVM和Java的字节码文件。

这里我们需要有一点共识,就是任何一门编程语言都需要转换为与平台相关的汇编指令才能够最终被硬件执行,比如C和C++都将我们的源代码直接编译成与CPU相关的汇编指令给CPU执行。

不同系列的CPU的体系架构不同,所以它们的汇编指令也有不同,比如X86架构的CPU对应于X86汇编指令,arm架构的CPU对应于arm汇编指令。

如果将程序源代码直接编译成与硬件相关的底层汇编指令,那么程序的跨平台性也就大打折扣,但执行性能相对较高。

为了实现平台无关性,Java的编译器javac并不是将Java的源程序直接编译成与平台相关的汇编指令,而是编译成一种中间语言,即Java的class字节码文件。字节码文件,顾名思义存的就是字节码,即一个一个的字节。

Java源码编译后的字节码文件是不能够直接被CPU执行的,那么该如何执行呢?

答案是JVM,为了让Java程序能够在不同的平台上执行,Java官方提供了针对于各个平台的Java虚拟机。

JVM运行于硬件层之上,屏蔽各种平台的差异性。

javac编译后的字节码文件统一由JVM来加载最后再转化成与硬件相关的机器指令被CPU执行。

知道了通过JVM来加载字节码文件,那么还有一个问题,就是JVM如何将字节码中的每个字节和我们写的Java源代码相关联,也就是JVM如何知道我们写的Java源代码对应于Class文件中的哪段十六进制,这段十六进制是干什么的,执行了什么功能?

所以这就需要定义一个JVM层面的规范,在JVM层面抽象出一些我们能够认识的指令助记符,这些指令助记符就是Java的字节码指令。

字节码文件为什么存储十六进制?

字节码文件里面存的并不是二进制,而是十六进制,这是因为二进制太长了,一个字节要由8位二进制组成。所以用十六进制标表示,两个十六进制就可以表示一个字节。

安装执行步骤

下载并执行JITWatch

下载JITWatch

首先去到JITWatch的官方开源仓库:github.com/AdoptOpenJD…

选择需要下载的版本,这里建议使用1.4.2版本,1.4.2+版本的会出现乱码问题。

JITWatch很折腾?有这篇文章在可以放心

执行JITWatch

根据自己的操作系统选择并解压后,进入到项目主目录,使用maven命令启动项目

 mvn clean compile exec:java

如果这里出现报错错误: 找不到或无法加载主类 org.adoptopenjdk.jitwatch.launch.LaunchUI,说明你的JDK没有自带JavaFX包。

这里我的建议是下载自带JavaFX的JDK如Oracle JDK 11+

在解决完问题命令执行成功后会弹出JITWatch的GUI界面:

JITWatch很折腾?有这篇文章在可以放心

快速运行JITWatch

按照顺序试运行解析默认代码

JITWatch很折腾?有这篇文章在可以放心

我们按照上图的顺序依次点击Sandbox-> Configure Sandbox,选择汇编语言。

这里正常来说这一步我们的Show Disassembly选项是不可选中的。这将会导致我们接下来执行Run的时候弹出框的右栏不显示东西。

这个问题我会带着大家在下面解决。

我们点击Run按钮:

JITWatch很折腾?有这篇文章在可以放心

弹出了代码的分析界面,分为左中右三栏,左边为Java源码,中间为Java字节码,右边为JIT后的汇编码,如果进行多次JIT编译,还能分别查看编译结果,如下图所示:

JITWatch很折腾?有这篇文章在可以放心

但是正如我们上面所说这里的Assembly栏大概率不会出现内容(参考这个提问:stackoverflow.com/questions/4…

如果需要出现内容在这一步的选项需要能够被选中:

JITWatch很折腾?有这篇文章在可以放心

大致意思是:这是 JITWatch 与 FCML 反汇编程序一起使用时出现的错误。

在网上查阅大量资料告知需要hsdis。如果没有这个东西,直接运行代码加上如下虚拟机参数后

 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

会得到如下提示:

 Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output Could not load hsdis-amd64.dll; library not loadable; PrintAssembly is disabled

于是接下来我们就来安装HSDIS

获取hsdis并正确执行JITWatch

什么是HSDIS?

HSDISHotSpot disassembler的缩写,要使用HSDIS需要下载hsdis-amd64.dylib

下载准备

安装Cygwin

镜像使用网易的,mirrors.163.com/,速度还算行

然后再Select Packages页面需要注意,在默认的基础上,需要额外安装的package有:

  • Devel - make
  • Devel - gcc-core
  • Devel - mingw64-x86_64-gcc-core
  • Devel - texinfo
  • Utils - diffutils

安装完之后启动Cygwin,则会在Cygwin的安装目录下的home下自动生成你的用户名命名的文件夹(下文记之为~

测试Cygwin

运行Cygwin,在弹出的命令行窗口输入:

 cygcheck -c cygwin

会打印出当前Cygwin的版本和运行状态,如果status是ok的话,则Cygwin运行正常:

 Cygwin Package Information
 Package              Version        Status
 cygwin               3.3.6-1        OK

接着可以测试一些基本环境是否成功安装:

 g++ --version
 make –version
 ...

准备binutils和hsdis

将下载的binutils解压到~.../home/用户名/binutils-2.27/ 将下载的openJDK源码/src/share/tools/hsdis解压到~.../home/用户名/hsdis/ 修改~/hsdis/Makefile文件,搜索LIBRARIES,将

 LIBRARIES = $(TARGET_DIR)/bfd/libbfd.a \ $(TARGET_DIR)/opcodes/libopcodes.a \ $(TARGET_DIR)/libiberty/libiberty.a

修改为:

 LIBRARIES = $(TARGET_DIR)/bfd/libbfd.a \ $(TARGET_DIR)/zlib/libz.a \ $(TARGET_DIR)/opcodes/libopcodes.a \ 
 $(TARGET_DIR)/libiberty/libiberty.a

保存,并且在Cygwin窗口输入命令

 cd ~/hsdis
 make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.27 #(最后的binutils路径需要与实际安装路径一致)

等待几分钟,如果最后没有报错,那么就build成功了,我们需要的hsdis-amd64.dll现在就在~/hsdis/build/Linux-amd64里面了,把它copy到$JAVA_HOME\bin\server下。

重新运行JITWatch

 mvn clean compile exec:java

这个时候弹出的JITWatch界面的Show Disassembly选项就是可选中的:

JITWatch很折腾?有这篇文章在可以放心

并且可以成功的运行解析代码:

JITWatch很折腾?有这篇文章在可以放心

JITWatch解析本地Java代码

添加虚拟机参数,输出日志文件

我们先在idea中给想要解析的Class配置虚拟机参数:

 -Xcomp
 -XX:+UnlockDiagnosticVMOptions
 -XX:+PrintAssembly
 -XX:+LogCompilation
 -XX:LogFile=jit.log

JITWatch很折腾?有这篇文章在可以放心

运行IDEA后,汇编代码不仅打印输出到终端,还会生成我们所需的日志文件:

JITWatch很折腾?有这篇文章在可以放心

用JITWatch进行可视化分析

首先点击 Config 按钮来设置Java源码文件、Class字节码文件所在路径:

JITWatch很折腾?有这篇文章在可以放心

然后点击 Open Log 来导入我们刚刚生成的日志文件,然后点击 Start 即可。现在我们可以从左侧选择我们需要分析的类,然后在右侧列出的方法上右击并选择 Show TriView 即可进行分析:

JITWatch很折腾?有这篇文章在可以放心

从下面可以看到,JITWatch可以同时显示源码、字节码、汇编,大大方便了我们的分析工作:

JITWatch很折腾?有这篇文章在可以放心

小结

JITWatch的安装还算是比较麻烦的,中间踩了好多坑,然后网上的文章大多感觉不是很全,于是借着自己做成功了记录一下,帮助一下研究或需要这个东西的人。

本章参考: