查看jvm运行时字节码指令

java方法编译后会生成字节码指令,在运行期字节码指令会被加载到JVM内存中,使用HSDB可以查看运行期的字节码指令

贴代码:

public class Test extends BaseClass {

     private Integer i=3;
     private static int a=90;
     {
       int d=34;
     }

     static {
       int a=1;
       int b=2;
       int c=a+b;
     }
     public Test(){
        short s=8;
     }

     public void add(int a,int b){
      Test test=this;
      int z=a+b;
      int x=3;
     }
     public static void main(String[] args){
     Test test=new Test();
     test.add(2,3);
    }
}

javac Test.java

输出字节码

public class Test extends BaseClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
....省略了其他方法及常量池
{
  public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method BaseClass."<init>":()V
         4: aload_0
         5: iconst_3
         6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         9: putfield      #3                  // Field i:Ljava/lang/Integer;
        12: bipush        34
        14: istore_1
        15: bipush        8
        17: istore_1
        18: return

  public void add(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=6, args_size=3    //本地变量表为6个长度,内容:this->0,a->1,b->2,test->3,z->4,x->5
         0: aload_0         //加载本地变量表slot0,入栈
         1: astore_3        //赋值给test  
         2: iload_1         //加载本地变量表slot1,入栈
         3: iload_2         //加载本地变量表slot2,入栈
         4: iadd            //执行iadd操作后,入栈 
         5: istore        4 //弹栈,入本地变量表slot4
         7: iconst_3        //将3入栈  
         8: istore        5 //弹栈,入本地变量表slot5
        10: return
   
  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=2, locals=3, args_size=0
         0: bipush        90
         2: putstatic     #7                  // Field a:I
         5: iconst_1
         6: istore_0
         7: iconst_2
         8: istore_1
         9: iload_0
        10: iload_1
        11: iadd
        12: istore_2
        13: return
}

jdb命令打断点调试 

> jdb -XX:+UseSerialGC -Xmx10m -XX:-UseCompressedOops

> stop in Test.add

> run Test

开启HSDB

> echo $JAVA_HOME

> cd %JAVA_HOME%\lib

> sudo java -cp sa-jdi.jar sun.jvm.hotspot.HSDB

jps 查看运行Test java的进程号 我这里拿到是4801

 

打开Tools->class Browser

点开add方法 可以得知该方法的签名与地址 0x000000010f6002f8

对比javap 展开add方法的字节码,是完全一样的

字节码指令被分配在constMethodOop对象的内存区域的末尾

接下来,分析add方法,在jvm内部所对应的methodOpp对象实例的内存结构及各个字段的内存地址

可以看出constMethodOop字段的内存址 0x000000010f6002b0,这个地址就是Test.add()方法在JVM内部所对应的constMethodOop对象实例的内存地址,而add方法的字节码指令就在constMethodOop对象实例的内存后面

对比这张表,算出ConstMethodOop占用的内存空间,共有44字节

根据内存对齐规则:

  整个类型实例所占空间必须是类型中宽度最大的字段所占内存的整数位

constMethodOop包含指针,如_constants是8个字节,那最终是48个字节

因此add()方法的字节码指令的开始地址:0x000000010f6002b0+0x30 = 0x000000010f6002e0

采用HSDB的mem命令

 加上选项2,表示连续输出两行

hsdb> mem 0x000000010f6002e0 2

0x000000010f6002e0: 0x060436601c1b4eca

0x000000010f6002e8: 0x29112600ffb10536

jvm中每个字节码指令都占1字节长度

按照字节码,在内存中分配的顺序,从低到高,即java方法的第一条字节码在低位,java方法的最后一条指令在高位,所以要进行逆转

0x000000010f6002e0:  ca 4e 1b 1c 60 36 04 06

0x000000010f6002e8:  36 05 b1 ff 00 26 11 29

对照字节码转16进制

    ca   4e               1b            1c           60      36          04        06            36        05      b1         ff   00    26    11    29

         astore_3     iload_1    iload_2   iadd   istore     slot4   iconst_3  istore  slot5  return

ca地址不对,是因为这个地址被打了断点

对照一下,是不是一样的

public void add(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=6, args_size=3    //本地变量表为6个长度,内容:this->0,a->1,b->2,test->3,z->4,x->5
         0: aload_0         //加载本地变量表slot0,入栈
         1: astore_3        //赋值给test  
         2: iload_1         //加载本地变量表slot1,入栈
         3: iload_2         //加载本地变量表slot2,入栈
         4: iadd            //执行iadd操作后,入栈 
         5: istore        4 //弹栈,入本地变量表slot4
         7: iconst_3        //将3入栈  
         8: istore        5 //弹栈,入本地变量表slot5
        10: return

另一种方式,那就是直接查看主线程的堆栈结构

很明显,断点处就是方法内存开始处

好了,最后推荐一个好用的vpn 加速度

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值