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;
    }
}

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."<init>":()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               <init>
   #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          // "<init>":()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."<init>":()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"

再次附上没有 -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."<init>":()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               <init>
   #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          // "<init>":()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."<init>":()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"

参考

《深入理解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方法的属性的解释)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值