• JVM之Class文件分析详解


    JVM之Class文件分析详解

    逐个字节分析Class文件。了解Class文件内部结构。

    原始类文件:

    这个类直接拿了知乎的一个类,分析是很简单,只是因为重新画图比较麻烦,不想再做重复的苦力工作(地址(https://zhuanlan.zhihu.com/p/23068093)ps:作者仅仅提供了类和图,并无解析。)

    package com.vonzhou.learn.jvm.klass;
    
    public class Foo {
        private int m;
    
        public int inc() {
            return m + 1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Class结构体

    一个Class文件可以用如下的结构体抽象:

    在这里插入图片描述

    Step by Step

    接下来就是对照着字节码和JVM规范阅读的过程,对自己多点耐心。

    Class魔数和版本

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    常量池计数器和常量池

    在这里插入图片描述

    注意:常量池内常量的真实数量是 常量池计数器-1

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    img

    在这里插入图片描述

    在这里插入图片描述

    img

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    img

    img

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    那么接下来就是这三个了:

    1556854982133

    访问标志

    1556855229233

    1556851149393

    这里

    img

    为什么是0021呢?因为 0X0001|0X0020 = 0X0021。

    类索引,父类索引

    1556855257629

    接下来的2B是this_class指向我们的类名, super_class指示父类。

    img

    img

    这里没有实现接口:

    img

    字段计数器和字段表集合

    fields_count以后进入字段表集合

    1556851584435

    1556851428143

    1556851512040

    img

    方法计数器和方法表集合

    首先进入方法计数器。

    1556852236787

    img

    1556852171723

    1556851428143

    从上可以看出,关键的不同点在于attribute_info字段。这是属性表集合,下面附上属性表集合的一般结构。

    1556852397696

    1556852498092

    从上面两个图可以看出属性表前两个字段时固定的,关键在于第三个字段各有不同,比如方法表的属性表Code的完整格式为下图

    1556853118948

    接下来就对Code属性表进行梳理:

    img

    img

    属性计数器和属性表集合

    1556856126125

    属性表集合中的SourceFile:1556854138367

    1556854215807

    由属性计数器后的0010计算十进制数为

    1556855978446

    下面的DEC为16,所以找到第16个常量为1556856030704

    没错了,是SourceFile

    img

    附上javap -version 验证解析结果

    使用javap解析出来的结果中没有包含LocalVariableTable字段,需要在使用javac编译java中时,加上-g的参数,生成的class文件中才带有LocalVariableTable的信息。LocalVariableTable属性:用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,非运行时必需属性,默认不会生成至Class文件中,可以使用Javac的-g:none或-g:vars关闭或要求生成该项属性信息。

    1556860378700

    另外:LineNumberTale属性:用于描述Java源码的行号与字节码行号之间的对应关系,非运行时必需属性,会默认生成至Class文件中,可以使用Javac的-g:none或-g:lines关闭或要求生成该项属性信息。

    1556860512094

    具体编译过程:

    javac -g -d . Foo.java
    
    
    javap -v com.vonzhou.learn.jvm.klass.Foo
    
    
    ca fe ba be 20 20 20 34 20 16 0a 20 04 20 12 09 20 03 20 13 07 20 14 07 20 15 01 20 01 6d 01 20 01 49 01 20 06 3c 69 6e 69 74 3e 01 20 03 28 29 56 01 20 04 43 6f 64 65 01 20 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 20 12 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01 20 04 74 68 69 73 01 20 21 4c 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 3b 01 20 03 69 6e 63 01 20 03 28 29 49 01 20 0a 53 6f 75 72 63 65 46 69 6c 65 01 20 08 46 6f 6f 2e 6a 61 76 61 0c 20 07 20 08 0c 20 05 20 06 01 20 1f 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 01 20 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 20 21 20 03 20 04 20 20 20 01 20 02 20 05 20 06 20 20 20 02 20 01 20 07 20 08 20 01 20 09 20 20 20 2f 20 01 20 01 20 20 20 05 2a b7 20 01 b1 20 20 20 02 20 0a 20 20 20 06 20 01 20 20 20 03 20 0b 20 20 20 0c 20 01 20 20 20 05 20 0c 20 0d 20 20 20 01 20 0e 20 0f 20 01 20 09 20 20 20 31 20 02 20 01 20 20 20 07 2a b4 20 02 04 60 ac 20 20 20 02 20 0a 20 20 20 06 20 01 20 20 20 07 20 0b 20 20 20 0c 20 01 20 20 20 07 20 0c 20 0d 20 20 20 01 20 10 20 20 20 02 20 11  
    
    
    E:JVM>javap -v com.vonzhou.learn.jvm.klass.Foo
    Classfile /E:/JVM/com/vonzhou/learn/jvm/klass/Foo.class
      Last modified 2019-5-3; size 391 bytes
      MD5 checksum 4d9e593620f49a9114d834ec5d923986
      Compiled from "Foo.java"
    public class com.vonzhou.learn.jvm.klass.Foo
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #4.#18         // java/lang/Object."":()V
       #2 = Fieldref           #3.#19         // com/vonzhou/learn/jvm/klass/Foo.m:I
       #3 = Class              #20            // com/vonzhou/learn/jvm/klass/Foo
       #4 = Class              #21            // java/lang/Object
       #5 = Utf8               m
       #6 = Utf8               I
       #7 = Utf8               
       #8 = Utf8               ()V
       #9 = Utf8               Code
      #10 = Utf8               LineNumberTable
      #11 = Utf8               LocalVariableTable
      #12 = Utf8               this
      #13 = Utf8               Lcom/vonzhou/learn/jvm/klass/Foo;
      #14 = Utf8               inc
      #15 = Utf8               ()I
      #16 = Utf8               SourceFile
      #17 = Utf8               Foo.java
      #18 = NameAndType        #7:#8          // "":()V
      #19 = NameAndType        #5:#6          // m:I
      #20 = Utf8               com/vonzhou/learn/jvm/klass/Foo
      #21 = Utf8               java/lang/Object
    {
      public com.vonzhou.learn.jvm.klass.Foo();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."":()V
             4: return
          LineNumberTable:
            line 3: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       5     0  this   Lcom/vonzhou/learn/jvm/klass/Foo;
    
      public int inc();
        descriptor: ()I
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: aload_0
             1: getfield      #2                  // Field m:I
             4: iconst_1
             5: iadd
             6: ireturn
          LineNumberTable:
            line 7: 0
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       7     0  this   Lcom/vonzhou/learn/jvm/klass/Foo;
    }
    SourceFile: "Foo.java"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    再次附上没有 -g 的结果:

    ca fe ba be 20 20 20 34 20 13 0a 20 04 20 0f 09 20 03 20 10 07 20 11 07 20 12 01 20 01 6d 01 20 01 49 01 20 06 3c 69 6e 69 74 3e 01 20 03 28 29 56 01 20 04 43 6f 64 65 01 20 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 20 03 69 6e 63 01 20 03 28 29 49 01 20 0a 53 6f 75 72 63 65 46 69 6c 65 01 20 08 46 6f 6f 2e 6a 61 76 61 0c 20 07 20 08 0c 20 05 20 06 01 20 1f 63 6f 6d 2f 76 6f 6e 7a 68 6f 75 2f 6c 65 61 72 6e 2f 6a 76 6d 2f 6b 6c 61 73 73 2f 46 6f 6f 01 20 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 20 21 20 03 20 04 20 20 20 01 20 02 20 05 20 06 20 20 20 02 20 01 20 07 20 08 20 01 20 09 20 20 20 1d 20 01 20 01 20 20 20 05 2a b7 20 01 b1 20 20 20 01 20 0a 20 20 20 06 20 01 20 20 20 03 20 01 20 0b 20 0c 20 01 20 09 20 20 20 1f 20 02 20 01 20 20 20 07 2a b4 20 02 04 60 ac 20 20 20 01 20 0a 20 20 20 06 20 01 20 20 20 07 20 01 20 0d 20 20 20 02 20 0e  
    
    
    E:JVM>javac  -d . Foo.java
    
    E:JVM>javap -v com.vonzhou.learn.jvm.klass.Foo
    Classfile /E:/JVM/com/vonzhou/learn/jvm/klass/Foo.class
      Last modified 2019-5-3; size 291 bytes
      MD5 checksum 45262c23d72e75c78347d2f05b918bee
      Compiled from "Foo.java"
    public class com.vonzhou.learn.jvm.klass.Foo
      minor version: 0
      major version: 52
      flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
       #1 = Methodref          #4.#15         // java/lang/Object."":()V
       #2 = Fieldref           #3.#16         // com/vonzhou/learn/jvm/klass/Foo.m:I
       #3 = Class              #17            // com/vonzhou/learn/jvm/klass/Foo
       #4 = Class              #18            // java/lang/Object
       #5 = Utf8               m
       #6 = Utf8               I
       #7 = Utf8               
       #8 = Utf8               ()V
       #9 = Utf8               Code
      #10 = Utf8               LineNumberTable
      #11 = Utf8               inc
      #12 = Utf8               ()I
      #13 = Utf8               SourceFile
      #14 = Utf8               Foo.java
      #15 = NameAndType        #7:#8          // "":()V
      #16 = NameAndType        #5:#6          // m:I
      #17 = Utf8               com/vonzhou/learn/jvm/klass/Foo
      #18 = Utf8               java/lang/Object
    {
      public com.vonzhou.learn.jvm.klass.Foo();
        descriptor: ()V
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=1, args_size=1
             0: aload_0
             1: invokespecial #1                  // Method java/lang/Object."":()V
             4: return
          LineNumberTable:
            line 3: 0
    
      public int inc();
        descriptor: ()I
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=1, args_size=1
             0: aload_0
             1: getfield      #2                  // Field m:I
             4: iconst_1
             5: iadd
             6: ireturn
          LineNumberTable:
            line 7: 0
    }
    SourceFile: "Foo.java"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    参考

    《深入理解Java虚拟机》周志明,

    另外找到的其他关于Class文件解析的文章有:

    https://www.cnblogs.com/timlong/p/8143839.html

    https://www.cnblogs.com/noteless/p/9540876.html#0

    https://www.jianshu.com/p/d0f3e361f92e

    https://www.jb51.net/article/116203.htm(这个有对文中没有详细解释的method方法的属性的解释)

  • 相关阅读:
    【C语言基础】循环
    websocket通信案例
    双非本科的保研总结
    JSP | oa项目增加用户登录的功能
    【跟踪算法汇总】
    sqlserver management studio(2008R2版本)添加注释列及默认值列
    云计算学习7——云计算OpenStack运维基础
    OpenGL编程学习笔记——交互与直线算法
    计算机网络之概述
    python 爬虫的开发环境配置
  • 原文地址:https://blog.csdn.net/asdfadafd/article/details/126743574