JVM字节码与代码优化

一.字节码查看
    将.java源文件编译成.class二进制字节码文件,运行该字节码文件
    
    1.将class字节码文件内容输出到文本文件当中
     javap -v xxx.class > xxx.txt
     
     第一个部分:
      显示生成class的java源文件的基本信息
        Classfile /C:/Users/FLC/Desktop/授课内容/授课案例/Y2170/day22/jvm_project/jvm_day01/target/classes/com/wdksoft/ClassTest.class
        Last modified 2020-3-11; size 585 bytes
        MD5 checksum 39fa2636495e5b4bf08da6decc537381
        Compiled from "ClassTest.java"
        public class com.wdksoft.ClassTest
        minor version: 0
        major version: 51
        flags: ACC_PUBLIC, ACC_SUPER
     
     第二个部分:显示该类所涉及到的常量池,共有35个常量
      Constant pool:
         #1 = Methodref          #5.#23         // java/lang/Object."<init>":()V
         #2 = Fieldref           #24.#25        // java/lang/System.out:Ljava/io/PrintStream;
         #3 = Methodref          #26.#27        // java/io/PrintStream.println:(I)V
         #4 = Class              #28            // com/wdksoft/ClassTest
         #5 = Class              #29            // java/lang/Object
         #6 = Utf8               <init>
         #7 = Utf8               ()V
         #8 = Utf8               Code
         #9 = Utf8               LineNumberTable
        #10 = Utf8               LocalVariableTable
        #11 = Utf8               this
        #12 = Utf8               Lcom/wdksoft/ClassTest;
        #13 = Utf8               main
        #14 = Utf8               ([Ljava/lang/String;)V
        #15 = Utf8               args
        #16 = Utf8               [Ljava/lang/String;
        #17 = Utf8               a
        #18 = Utf8               I
        #19 = Utf8               b
        #20 = Utf8               c
        #21 = Utf8               SourceFile
        #22 = Utf8               ClassTest.java
        #23 = NameAndType        #6:#7          // "<init>":()V
        #24 = Class              #30            // java/lang/System
        #25 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
        #26 = Class              #33            // java/io/PrintStream
        #27 = NameAndType        #34:#35        // println:(I)V
        #28 = Utf8               com/wdksoft/ClassTest
        #29 = Utf8               java/lang/Object
        #30 = Utf8               java/lang/System
        #31 = Utf8               out
        #32 = Utf8               Ljava/io/PrintStream;
        #33 = Utf8               java/io/PrintStream
        #34 = Utf8               println
        #35 = Utf8               (I)V
     
     
     第三个部分:显示该类的构造器,编译器自动生成一个无参构造
      public com.wdksoft.ClassTest();
      descriptor: ()V
      flags: ACC_PUBLIC
      Code:
        stack=1, locals=1, args_size=1
        0: aload_0
        1: invokespecial #1                  // Method java/lang/Object."<init>":()V
        4: return
        LineNumberTable:
       line 3: 0
        LocalVariableTable:
       Start  Length  Slot  Name   Signature
        0       5     0  this   Lcom/wdksoft/ClassTest;
     
     第四部分:显示main方法的信息
      public static void main(java.lang.String[]);
       descriptor: ([Ljava/lang/String;)V    方法的描述,V代表返回值为void
       flags: ACC_PUBLIC, ACC_STATIC     方法修饰符 public  static
       Code:
         stack=2, locals=4, args_size=1    stack代表操作栈的大小   locals本地变量表大小    args_size代表参数个数
         0: iconst_2        将数据2压入到操作栈当中,位于栈顶
         1: istore_1        从操作栈当中弹出一个数据,放到本地变量表当中,下标为1,0是this,操作栈当中数据清空
         2: iconst_5        将数据5压入到操作栈当中,位于栈顶
         3: istore_2        从操作栈当中弹出一个数据,放到本地变量表当中,下标为2,0是this,操作栈当中数据清空
         4: iload_2         将本地变量表中的下标为2的数据压入到操作站
         5: iload_1         将本地变量表中的下标为1的数据压入到操作站
         6: isub         将操作栈中的两个数据相减
         7: istore_3        将相减的结果压入到本地本地变量表当中,下标为3
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: iload_3         将本地变量表中下标为3的数据压入到操作站
        12: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        15: return         返回
         LineNumberTable:        行号列表
        line 5: 0
        line 6: 2
        line 7: 4
        line 8: 8
        line 9: 15
         LocalVariableTable:       
        Start  Length  Slot  Name   Signature
         0      16     0  args   [Ljava/lang/String;
         2      14     1     a   I
         4      12     2     b   I
         8       8     3     c   I
    
    
    
   二.动态字节技术
    在程序运行或者编译时期,通过动态字节码技术对类新增,删除,修改类的内部结构,包括字段和方法
    动态字节码技术应用场景:AOP,Lombok,动态修改class文件等等
    
    字节码操作类库:
     1.BCEL
     2.ASM:轻量级的Java字节码操作框架,SpringAOP底层基于ASM字节码技术
     3.CGLIB 基于ASM
     4.javassist
    

通过javap命令查看class文件的字节码内容

  1.1创建一个简单的测试类:

 
public class Test {
    public static void main(String[] args) {
        int a=2;
        int b=5;
        int c=b-a;
        System.out.println(c);
    }
}

  1.2 cmd打开窗口,使用如下命令:

javap ‐v Test.class > Test.txt

  1.3查看Test01.txt文件,内容如下:

JVM字节码与代码优化
Classfile /G:/学习/Y2/Test/Test01.class
  Last modified 2020-3-9; size 576 bytes
  MD5 checksum e263d731887a9c6376ddab948c1efa19
  Compiled from "Test01.java"
public class com.my.Test.Test01
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#23         // java/lang/Object."<init>":()V
   #2 = Fieldref           #24.#25        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Methodref          #26.#27        // java/io/PrintStream.println:(I)V
   #4 = Class              #28            // com/wn/Test/Test01
   #5 = Class              #29            // java/lang/Object
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               LocalVariableTable
  #11 = Utf8               this
  #12 = Utf8               Lcom/wn/Test/Test01;
  #13 = Utf8               main
  #14 = Utf8               ([Ljava/lang/String;)V
  #15 = Utf8               args
  #16 = Utf8               [Ljava/lang/String;
  #17 = Utf8               a
  #18 = Utf8               I
  #19 = Utf8               b
  #20 = Utf8               c
  #21 = Utf8               SourceFile
  #22 = Utf8               Test01.java
  #23 = NameAndType        #6:#7          // "<init>":()V
  #24 = Class              #30            // java/lang/System
  #25 = NameAndType        #31:#32        // out:Ljava/io/PrintStream;
  #26 = Class              #33            // java/io/PrintStream
  #27 = NameAndType        #34:#35        // println:(I)V
  #28 = Utf8               com/wn/Test/Test01
  #29 = Utf8               java/lang/Object
  #30 = Utf8               java/lang/System
  #31 = Utf8               out
  #32 = Utf8               Ljava/io/PrintStream;
  #33 = Utf8               java/io/PrintStream
  #34 = Utf8               println
  #35 = Utf8               (I)V
{
  public com.my.Test.Test01();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/wn/Test/Test01;

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


   
   二.代码优化

所谓代码优化是指对程序代码进行等价(指不改变程序的运行结果)变换。程序代码可以是中间代码(如四元式代码),也可以是计算机
在不改变程序运行效果的前提下,对被编译的程序进行等价变换,使之能生成更加高效的目标代码。
 
明确一个概念,对方法的调用,即使方法中只有一句 语句,也是有消耗的。
for (int i = 0; i < list.size(); i++)
{...}
建议替换为:
int length = list.size();
for (int i = 0, i < length; i++)
{...}