【IDEA】使用IDEA和hsdis-amd64.dll工具查看运行Java代码生成的汇编指令

46 篇文章 1 订阅

前言

注意:javap是为了让我们看.class字节码文件,因为直接看,不太方便;而.class在jvm中,需要进一步转为话硬件能识别的汇编语言(当然,进cpu之前,需要进一步把汇编语言再转为二进制形式),本篇目的就是为了查看汇编语言,即反汇编。

看.class字节码请参考《javap的使用(对字节代码进行反编译工具)》

HSDIS

HSDIS(HotSpot disassembler),一个Sun官方推荐的HotSpot虚拟机JIT编译代码的反汇编插件,其实际上就是一个动态库。这里我们直接从网上下载与我们系统对应的编译后文件,然后直接将其放置到JDK的bin目录下即可

1.下载工具hsdis-amd64.dll反汇编程序插件

http://vorboss.dl.sourceforge.net/project/fcml/fcml-1.1.1/hsdis-1.1.1-win32-amd64.zip

http://vorboss.dl.sourceforge.net/project/fcml/fcml-1.1.1/hsdis-1.1.1-win32-i386.zip

注意:如果是32位的jdk,需要下载32位的dll

  • 将hsdis-amd64.dll放在 $JAVA_HOME/jre/bin/server 目录下

    注意目录是jre的目录

  • 运行时添加参数: -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

在这里插入图片描述

查看Volatile例子

-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*VolatileTest.refresh

-XX:CompileCommand=compileonly,VolatileTest.refresh表示过滤,仅显示VolatileTest.refresh,注意号不能丢,除非你提供类的全路径名称

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class VolatileTest {
    //循环的终止条件,加volatile会影响运行结果
    private static volatile boolean initFlag = false;

    private  static int counter = 0;

    public static void refresh(){
        log.info("refresh data.......");
        initFlag = true;
        log.info("refresh data success.......");
    }


    public static void main(String[] args){
        //线程A负责循环,直至收到终止的信令才会停下来
        Thread threadA = new Thread(()->{
            while (!initFlag){
                //System.out.println("runing");
                counter++;
            }
            log.info("线程:" + Thread.currentThread().getName()
                    + "当前线程嗅探到initFlag的状态的改变");
        },"threadA");
        threadA.start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //b线程负责通知A终止循环
        Thread threadB = new Thread(()->{
            refresh();
        },"threadB");
        threadB.start();
    }
}

关键输出信息:

 0x0000000002bc7057: lock add dword ptr [rsp],0h  ;*putstatic initFlag
                                                ; - com.yg.edu.jmm.VolatileTest::refresh@11 (line 18)

能看到initFlag变量前有lock标识

错误

如果不下载dlll,运行时会报错:

Could not load hsdis-amd64.dll; library not loadable; PrintAssembly is disabled

过程解释

-XX:CompileCommand作用:
参见《你假笨JVM参数 - 003 CompileCommand》

含义:


该参数用于定制编译需求,比如过滤某个方法不做JIT编译
若未指定方法描述符,则对全部同名方法执行命令操作,具体如何指定见下文[举例]
可使用星号通配符(*)指定类或方法,具体如何使用见下文[举例]
该参数可多次指定,或使用 换行符(\n)分隔参数后的多个命令
解析完该命令后,JIT编译器会读取.hotspot_compiler文件中的命令,该参数也可写在.hotspot_compiler文件中
可使用-XX:CompileCommandFile指定.hotspot_compiler文件为其他文件

用法:

-XX:CompileCommand=command,method[,option]

命令:

exclude,跳过编译指定的方法
compileonly,只编译指定的方法
inline/dontinline,设置是否内联指定方法
print,打印生成的汇编代码
break,JVM以debug模式运行时,在方法编译开始处设置断点
quiet,不打印在此命令之后、通过-XX:CompileCommand指定的编译选项
log,记录指定方法的编译日志,若未指定,则记录所有方法的编译日志
其他命令,option,help

举例:


1. 设置编译器跳过编译com.jvmpocket.Dummy类test方法的4种写法
-XX:CompileCommand=exclude,com/jvmpocket/Dummy.test
-XX:CompileCommand=exclude,com/jvmpocket/Dummy::test
-XX:CompileCommand=exclude,com.jvmpocket.Dummy::test
-XX:CompileCommand="exclude com/jvmpocket/Dummy test"
2. 设置编译器只跳过编译java.lang.String类int indexOf(String)方法
-XX:CompileCommand="exclude,java/lang/String.indexOf,(Ljava/lang/String;)I"
3. 设置编译器跳过编译所有类的indexOf方法
-XX:CompileCommand=exclude,*.indexOf

参考:
《使用IDEA查看运行Java代码生成的汇编指令》

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值