zoukankan      html  css  js  c++  java
  • 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文件,内容如下:

    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++)
    {...}
  • 相关阅读:
    vue学习简单入门
    Python3基础学习
    MySQL数据库索引详解
    使用nginx部署多个前端项目
    基于SpringBoot2.x和tkMapper快速搭建微服务项目脚手架工程
    安装篇-Linux安装maven3.5.2
    安装篇-安装maven3.6.1
    安装篇-安装Idea2019.3.3
    安装篇-jdk1.8安装
    【错误解决】Intellj(IDEA) warning no artifacts configured
  • 原文地址:https://www.cnblogs.com/F017/p/12462566.html
Copyright © 2011-2022 走看看