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
                    
       案例研究:

      1. 研究 i++ 与 ++i 的不同
          我们都知道,i++表示,先返回再+1,++i表示,先+1再返回。它的底层是怎么样的呢? 我们一起探究下。

           i++:

                    0: iconst_1 //将数字1压入到操作栈
                    1: istore_1 //将数字1从操作栈弹出,压入到本地变量表中,下标为1
                    2: iload_1 //从本地变量表中获取下标为1的数据,压入到操作栈中
                    3: iinc 1, 1 // 将本地变量中的1,再+1
                    6: istore_2 // 将数字1从操作栈弹出,压入到本地变量表中,下标为2
                    7: getstatic #6 // Field
                    java/lang/System.out:Ljava/io/PrintStream;
                    10: iload_2 //从本地变量表中获取下标为2的数据,压入到操作栈中
                    11: invokevirtual #7 // Method
                    java/io/PrintStream.println:(I)V
                    14: return        


                      
                        ++i:

                    0: iconst_1 //将数字1压入到操作栈
                    1: istore_1 //将数字1从操作栈弹出,压入到本地变量表中,下标为1
                    2: iinc 1, 1// 将本地变量中的1,再+1
                    5: iload_1 //从本地变量表中获取下标为1的数据(2),压入到操作栈中
                    6: istore_2 //将数字2从操作栈弹出,压入到本地变量表中,下标为2
                    7: getstatic #6 // Field
                    java/lang/System.out:Ljava/io/PrintStream;
                    10: iload_2 //从本地变量表中获取下标为2的数据(2),压入到操作栈中
                    11: invokevirtual #7 // Method
                    java/io/PrintStream.println:(I)V
                    14: return


                        区别:
                        i++
                        只是在本地变量中对数字做了相加,并没有将数据压入到操作栈
                        将前面拿到的数字1,再次从操作栈中拿到,压入到本地变量中
                        ++i
                        将本地变量中的数字做了相加,并且将数据压入到操作栈
                        将操作栈中的数据,再次压入到本地变量中

                    
                二.动态字节码技术
                    在程序运行或者编译时期,通过动态字节码技术对类新增,删除,修改类的内部结构,包括字段和方法
                    动态字节码技术应用场景:AOP,Lombok,动态修改class文件等等

  • 相关阅读:
    Java中的函数传递
    Java中的native关键字浅析(JNI)
    抽象类简单举例
    提升java性能的基本方法
    Java中throw和throws的区别
    直接插入排序以及java实现
    Java实现定时任务的三种方法
    Java求素数的算法
    Hibernate基于注解的元数据
    Java多线程之Callable接口的实现
  • 原文地址:https://www.cnblogs.com/chx9832/p/12461823.html
Copyright © 2011-2022 走看看