JVM优化:JVM字节码入门demo

本文只是简单入门demo演示,大家想要深入了解还是看官网文档或相关书籍比较好.

英文好的可以去https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

当然,如果英文不好的,可以看https://blog.csdn.net/weelyy/article/details/78969412

当然,大家如果有好的其它资源,欢迎推荐

java源码

package cn.jvm;

public class Test1 {

	public static void main(String[] args) {
		int a=5;
		int b=9;
		int c=11;
		int d=a+b-c;
		System.out.println(d);
	}

}

class文件:

一般文本编辑器打开

说实话,能看懂这堆乱码的,那都是鬼才.

漱壕   4 %  cn/jvm/Test1  java/lang/Object <init> ()V Code
  	   LineNumberTable LocalVariableTable this Lcn/jvm/Test1; main ([Ljava/lang/String;)V	    java/lang/System   out Ljava/io/PrintStream;
    java/io/PrintStream   println (I)V args [Ljava/lang/String; a I b c d 
SourceFile 
Test1.java !               /     *??   
                 
   	       ~     <	=>`d6???   
             	  
      4                      !    	 "    #    $

16进制编辑器打开(在编辑器中是以表格的形式展示,拷贝出来就没有表格了)

16进制编辑器打开后,可以看了.不过,能看懂的人,脑子都不是一般人能比的.所以,作为普通人,我们还是找个更简单的方式.

CAFEBABE00000034002507000201000C636E2F6A766D2F54657374310700040100106A6176612F6C616E672F4F626A6563740100063C696E69743E010003282956010004436F64650A000300090C0005000601000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C650100047468697301000E4C636E2F6A766D2F54657374313B0100046D61696E010016285B4C6A6176612F6C616E672F537472696E673B295609001100130700120100106A6176612F6C616E672F53797374656D0C001400150100036F75740100154C6A6176612F696F2F5072696E7453747265616D3B0A001700190700180100136A6176612F696F2F5072696E7453747265616D0C001A001B0100077072696E746C6E01000428492956010004617267730100135B4C6A6176612F6C616E672F537472696E673B010001610100014901000162010001630100016401000A536F7572636546696C6501000A54657374312E6A617661002100010003000000000002000100050006000100070000002F00010001000000052AB70008B100000002000A00000006000100000003000B0000000C000100000005000C000D00000009000E000F000100070000007E0002000500000018083C10093D100B3E1B1C601D643604B200101504B60016B100000002000A0000001A00060000000700020008000500090008000A000F000B0017000C000B00000034000500000018001C001D000000020016001E001F0001000500130020001F0002000800100021001F0003000F00090022001F

使用javap命令,转成比较容易看懂的

javap -v Test1.class > Test1.txt
#当然,如果只看方法部分,可以使用 -c
//class字节码内容
Classfile /E:/code/test02/bin/cn/jvm/Test1.class
  Last modified 2020-5-13; size 589 bytes
  MD5 checksum e7b5f7b08dc9a21fcd20374c4639474f
  Compiled from "Test1.java"
public class cn.jvm.Test1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // cn/jvm/Test1
   #2 = Utf8               cn/jvm/Test1
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcn/jvm/Test1;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Fieldref           #17.#19        // java/lang/System.out:Ljava/io/PrintStream;
  #17 = Class              #18            // java/lang/System
  #18 = Utf8               java/lang/System
  #19 = NameAndType        #20:#21        // out:Ljava/io/PrintStream;
  #20 = Utf8               out
  #21 = Utf8               Ljava/io/PrintStream;
  #22 = Methodref          #23.#25        // java/io/PrintStream.println:(I)V
  #23 = Class              #24            // java/io/PrintStream
  #24 = Utf8               java/io/PrintStream
  #25 = NameAndType        #26:#27        // println:(I)V
  #26 = Utf8               println
  #27 = Utf8               (I)V
  #28 = Utf8               args
  #29 = Utf8               [Ljava/lang/String;
  #30 = Utf8               a
  #31 = Utf8               I
  #32 = Utf8               b
  #33 = Utf8               c
  #34 = Utf8               d
  #35 = Utf8               SourceFile
  #36 = Utf8               Test1.java
{
  public cn.jvm.Test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/jvm/Test1;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
         0: iconst_5
         1: istore_1
         2: bipush        9
         4: istore_2
         5: bipush        11
         7: istore_3
         8: iload_1
         9: iload_2
        10: iadd
        11: iload_3
        12: isub
        13: istore        4
        15: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
        18: iload         4
        20: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
        23: return
      LineNumberTable:
        line 6: 0
        line 7: 2
        line 8: 5
        line 9: 8
        line 10: 15
        line 11: 23
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      24     0  args   [Ljava/lang/String;
            2      22     1     a   I
            5      19     2     b   I
            8      16     3     c   I
           15       9     4     d   I
}
SourceFile: "Test1.java"

//这一部分,显示的是class文件的一些相关信息,比如路径,修改时间,大小,编译的java文件,版本号,权限等
Classfile /E:/code/test02/bin/cn/jvm/Test1.class
  Last modified 2020-5-13; size 589 bytes
  MD5 checksum e7b5f7b08dc9a21fcd20374c4639474f
  Compiled from "Test1.java"
public class cn.jvm.Test1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
 

权限标识符

名称说明
ACC_PUBLIC0x0001public 可以从其程序包外部进行访问。
ACC_FINAL0x0010final 不能被继承
ACC_SUPER0x0020用于兼容早期编译器,新编译器都有该标志
ACC_INTERFACE0x0200接口 而不是一个类。
ACC_ABSTRACT0x0400抽象类 不能实例化。
ACC_SYNTHETIC0x1000由编译器产生,在源代码中不存在。
ACC_ANNOTATION0x2000注释类型,
ACC_ENUM0x4000枚举类型
//常量池部分,共有36个.常量池的索引从1开始
Constant pool:
   #1 = Class              #2         //Class代表类或接口的引用,什么类呢,看 #2,原来是cn/jvm/Test1
   #2 = Utf8               cn/jvm/Test1  //编码为Utf8的字符串cn/jvm/Test1
   #3 = Class              #4             //Class代表类或接口的引用   #4 java/lang/Object
   #4 = Utf8               java/lang/Object //编码为Utf8的字符串java/lang/Object
   #5 = Utf8               <init>           //编码为Utf8的字符串<init>
   #6 = Utf8               ()V              //编码为Utf8的字符串()V  ,无参,返回void
   #7 = Utf8               Code				//编码为Utf8的字符串Code	
   #8 = Methodref          #3.#9          //方法的引用, #3.#9,#3调用#9 也就是java/lang/Object."<init>":()V  
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable  //编码为Utf8的字符串LineNumberTable
  #11 = Utf8               LocalVariableTable //编码为Utf8的字符串LocalVariableTable
  #12 = Utf8               this	          //编码为Utf8的字符串this
  #13 = Utf8               Lcn/jvm/Test1;   //编码为Utf8的字符串Lcn/jvm/Test1;
  #14 = Utf8               main    //编码为Utf8的字符串main
  #15 = Utf8               ([Ljava/lang/String;)V  //编码为Utf8的字符串 ([Ljava/lang/String;)V  参数是String数组,返回值是void
  #16 = Fieldref           #17.#19        // java/lang/System.out:Ljava/io/PrintStream;
  #17 = Class              #18            // java/lang/System
  #18 = Utf8               java/lang/System  //编码为Utf8的字符串 java/lang/System
  #19 = NameAndType        #20:#21        // out:Ljava/io/PrintStream;
  #20 = Utf8               out      //编码为Utf8的字符串   out
  #21 = Utf8               Ljava/io/PrintStream;  //编码为Utf8的字符串 Ljava/io/PrintStream; PrintStream类
  #22 = Methodref          #23.#25        // java/io/PrintStream.println:(I)V
  #23 = Class              #24            // java/io/PrintStream
  #24 = Utf8               java/io/PrintStream  //编码为Utf8的字符串  java/io/PrintStream
  #25 = NameAndType        #26:#27        // println:(I)V
  #26 = Utf8               println  //编码为Utf8的字符串  println
  #27 = Utf8               (I)V   //编码为Utf8的字符串 (I)V   参数是int 类型,返回是void
  #28 = Utf8               args    //编码为Utf8的字符串 args
  #29 = Utf8               [Ljava/lang/String;   //编码为Utf8的字符串 [Ljava/lang/String;  String数组
  #31 = Utf8               I          //编码为Utf8的字符串 I
  #32 = Utf8               b          //编码为Utf8的字符串 b
  #33 = Utf8               c          //编码为Utf8的字符串 c
  #34 = Utf8               d          //编码为Utf8的字符串 d
  #35 = Utf8               SourceFile //编码为Utf8的字符串SourceFile
  #36 = Utf8               Test1.java //编码为Utf8的字符串  Test1.java

常量类型

Constant Type(常量类型)Value说明
CONSTANT_Utf81UTF-8编码的字符串
CONSTANT_Integer3整形常量
CONSTANT_Float4浮点型常量
CONSTANT_Long5长整型常量
CONSTANT_Double6双精度浮点型常量
CONSTANT_Class7类或接口的符号引用
CONSTANT_String8字符串类型常量
CONSTANT_Fieldref9字段的符号引用
CONSTANT_Methodref10类中方法的符号引用
CONSTANT_InterfaceMethodref11接口中方法的符号引用
CONSTANT_NameAndType12字段或方法的符号引用
CONSTANT_MethodHandle15表示方法句柄
CONSTANT_MethodType16标志方法类型
CONSTANT_InvokeDynamic18表示一个动态方法调用点

字段描述符

FieldType term类型说明
Bbytesigned byte
CcharUnicode character code point in the Basic Multilingual Plane, encoded with UTF-16
Ddoubledouble-precision floating-point value
Ffloatsingle-precision floating-point value
Iintinteger
Jlonglong integer
L ClassName ;referencean instance of class ClassName
Sshortsigned short
Zbooleantrue or false
[referenceone array dimension
//方法信息
//构造方法
public cn.jvm.Test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcn/jvm/Test1;

//main方法
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=5, args_size=1
     //操作栈大小为2,本地变量有5个,参数个数是1
         0: iconst_5                //将数字5压到操作栈栈顶
         1: istore_1	            //从操作栈中弹出一个数(5),放入到下表为1的本地变量中,非静态函数本地变量中下表为0的是this
         2: bipush        9		  //将一个byte数量9压倒栈顶
         4: istore_2			//将栈里的数(9)弹出放到本地变量表中,下表为2的位置
         5: bipush        11   //将一个byte数量11压倒栈顶
         7: istore_3        //将栈里的数(11)弹出放到本地变量表中,下表为2的位置
         8: iload_1      //将本地变量表中下表为1的数压入栈中  5
         9: iload_2 	 //将本地变量表中下表为2的数压入栈中  9
        10: iadd	    //栈中两个数相加  14
        11: iload_3	     //将本地变量表中下表为3的数压入栈中  11
        12: isub          //栈中数字相减  
        13: istore        4      //将栈中数字弹出,放到本地变量表中的4
        15: getstatic     #16        //获取指定类的静态域,并将其值压入栈顶         // Field java/lang/System.out:Ljava/io/PrintStream;     
        18: iload         4        //将本地变量表中下表为4的数压入栈中 
        20: invokevirtual #22       //调用实例方法          // Method java/io/PrintStream.println:(I)V
        23: return           //返回

jvm指令

名称说明
iconst_5将int类型常量5压到操作栈栈顶
istore_1从操作栈中弹出一个数,放入到下表为1的本地变量
bipush 9将byte类型常量9压到操作栈栈顶
iload_1将本地变量表中下表为1的数压入栈中
iadd栈顶两int数值相加,并且结果进栈
isub栈顶两int型数值相减,并且结果进栈
getstatic获取指定类的静态域,并将其值压入栈顶
invokevirtual调用实例方法
return当前方法返回void

更详细的内容,可以去看官网的JVM指令文档,可以是https://www.cnblogs.com/lsy131479/p/11201241.html或者https://blog.csdn.net/zhangpan19910604/article/details/52254053这些文章

//行数对比,
LineNumberTable:
        line 6: 0    //java中的第6行,对比上面的0
        line 7: 2    java中的第7行,对比上面的2
        line 8: 5
        line 9: 8
        line 10: 15
        line 11: 23
//本地变量
LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      24     0  args   [Ljava/lang/String;
            2      22     1     a   I
            5      19     2     b   I
            8      16     3     c   I
           15       9     4     d   I
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值