如何实现一个Java Class解析器

9 篇文章 0 订阅
3 篇文章 0 订阅

最近在写一个私人项目,名字叫做ClassAnalyzerClassAnalyzer的目的是能让我们对Java Class文件的设计与结构能够有一个深入的理解。主体框架与基本功能已经完成,还有一些细节功能日后再增加。实际上JDK已经提供了命令行工具javap来反编译Class文件,但本篇文章将阐明我实现解析器的思路。

 

Class文件


作为类或者接口信息的载体,每个Class文件都完整的定义了一个类。为了使Java程序可以“编写一次,处处运行”,Java虚拟机规范Class文件进行了严格的规定。构成Class文件的基本数据单位是字节,这些字节之间不存在任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,单个字节无法表示的数据由多个连续的字节来表示。

根据Java虚拟机规范,Class文件采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。Java虚拟机规范定义了u1u2u4u8来分别表示1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者是字符串。表是由多个无符号数或者其它表作为数据项构成的复合数据类型,表用于描述有层次关系的复合结构的数据,因此整个Class文件本质上就是一张表。在ClassAnalyzer中,byteshortintlong分别对应u1u2u4u8数据类型,Class文件被描述为如下Java类。

public class ClassFile {

    public U4 magic; // magic

    public U2 minorVersion; // minor_version

    public U2 majorVersion; // major_version

    public U2 constantPoolCount; // constant_pool_count

    public ConstantPoolInfo[] cpInfo; // cp_info

    public U2 accessFlags; // access_flags

    public U2 thisClass; // this_class

    public U2 superClass; // super_class

    public U2 interfacesCount; // interfaces_count

    public U2[] interfaces; // interfaces

    public U2 fieldsCount; // fields_count

    public FieldInfo[] fields; // fields

    public U2 methodsCount; // methods_count

    public MethodInfo[] methods; // methods

    public U2 attributesCount; // attributes_count

    public BasicAttributeInfo[] attributes; // attributes

}

 

如何解析


组成Class文件的各个数据项中,例如魔数、Class文件的版本、访问标志、类索引和父类索引等数据项,它们在每个Class文件中都占用固定数量的字节,在解析时只需要读取相应数量的字节。除此之外,需要灵活处理的主要包括4部分:常量池、字段表集合、方法表集合和属性表集合。字段和方法都可以具备自己的属性,Class本身也有相应的属性,因此,在解析字段表集合和方法表集合的同时也包含了属性表集合的解析。

常量池占据了Class文件很大一部分的数据,用于存储所有的常量信息,包括数字和字符串常量、类名、接口名、字段名和方法名等。Java虚拟机规范定义了多种常量类型,每一种常量类型都有自己的结构。常量池本身是一个表,在解析时有几点需要注意。

  • 每个常量类型都通过一个u1类型的tag来标识。

  • 表头给出的常量池大小(constantPoolCount)比实际大1,例如,如果constantPoolCount等于47,那么常量池中有46项常量。

  • 常量池的索引范围从1开始,例如,如果constantPoolCount等于47,那么常量池的索引范围为1 ~ 46。设计者将第0项空出来的目的是用于表达“不引用任何一个常量池项目”。
  • 如果一个CONSTANT_Long_infoCONSTANT_Double_info结构的项在常量池中的索引为n,则常量池中下一个有效的项的索引为n+2,此时常量池中索引为n+1的项有效但必须被认为不可用。
  • CONSTANT_Utf8_info型常量的结构中包含一个u1类型的tag、一个u2类型的length和由lengthu1类型组成的bytes,这length字节的连续数据是一个使用MUTF-8Modified UTF-8)编码的字符串。MUTF-8UTF-8并不兼容,主要区别有两点:一是null字符会被编码成2字节(0xC00x80);二是补充字符是按照UTF-16拆分为代理对分别编码的,相关细节可以看这里(变种UTF-8)

属性表用于描述某些场景专有的信息,Class文件、字段表和方法表都有相应的属性表集合。Java虚拟机规范定义了多种属性,ClassAnalyzer目前实现了对常用属性的解析。与常量类型的数据项不同,属性并没有一个tag来标识属性的类型,但是每个属性都包含有一个u2类型的attribute_name_indexattribute_name_index指向常量池中的一个CONSTANT_Utf8_info类型的常量,该常量包含着属性的名称。在解析属性时,ClassAnalyzer正是通过attribute_name_index指向的常量对应的属性名称来得知属性的类型。

字段表用于描述类或者接口中声明的变量,字段包括类级变量以及实例级变量。字段表的结构包含一个u2类型的access_flags、一个u2类型的name_index、一个u2类型的descriptor_index、一个u2类型的attributes_countattributes_countattribute_info类型的attributes。我们已经介绍了属性表的解析,attributes的解析方式与属性表的解析方式一致。

Class的文件方法表采用了和字段表相同的存储格式,只是access_flags对应的含义有所不同。方法表包含着一个重要的属性:Code属性。Code属性存储了Java代码编译成的字节码指令,在ClassAnalyzer中,Code对应的Java类如下所示(仅列出了类属性)。

public class Code extends BasicAttributeInfo {

    private short maxStack;

    private short maxLocals;

    private long codeLength;

    private byte[] code;

    private short exceptionTableLength;

    private ExceptionInfo[] exceptionTable;

    private short attributesCount;

    private BasicAttributeInfo[] attributes;

    ...

    private class ExceptionInfo {

        public short startPc;

        public short endPc;

        public short handlerPc;

        public short catchType;

        ...

    }

}

Code属性中,codeLengthcode分别用于存储字节码长度和字节码指令,每条指令即一个字节(u1类型)。在虚拟机执行时,通过读取code中的一个个字节码,并将字节码翻译成相应的指令。另外,虽然codeLength是一个u4类型的值,但是实际上一个方法不允许超过65535条字节码指令。

 

代码实现


ClassAnalyzer的源码已放在了GitHub上。在ClassAnalyzerREADME中,我以一个类的Class文件为例,对该Class文件的每个字节进行了分析,希望对大家的理解有所帮助。

 

Demo

TestClass.java

package org.tinylcy;

public class TestClass implements Cloneable {

    public static final String TAG = "tinylcy";
    private int num;

    public void inc() {
        num++;
    }

    public int exception() {
        int x;
        try {
            x = 1;
            return x;
        } catch (Exception e) {
            x = 2;
            return x;
        } finally {
            x = 3;
        }
    }

    public static void showTag() {
        System.out.println(TAG);
    }
}

TestClass.class

cafe babe 0000 0031 0030 0a00 0800 1f09
0005 0020 0700 2109 0022 0023 0700 2408
0025 0a00 2600 2707 0028 0700 2901 0003
5441 4701 0012 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 0100 0d43 6f6e 7374
616e 7456 616c 7565 0100 036e 756d 0100
0149 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 124c 6f63
616c 5661 7269 6162 6c65 5461 626c 6501
0004 7468 6973 0100 174c 6f72 672f 7469
6e79 6c63 792f 5465 7374 436c 6173 733b
0100 0369 6e63 0100 0965 7863 6570 7469
6f6e 0100 0328 2949 0100 0178 0100 0165
0100 154c 6a61 7661 2f6c 616e 672f 4578
6365 7074 696f 6e3b 0100 0773 686f 7754
6167 0100 0a53 6f75 7263 6546 696c 6501
000e 5465 7374 436c 6173 732e 6a61 7661
0c00 0f00 100c 000d 000e 0100 136a 6176
612f 6c61 6e67 2f45 7863 6570 7469 6f6e
0700 2a0c 002b 002c 0100 156f 7267 2f74
696e 796c 6379 2f54 6573 7443 6c61 7373
0100 0774 696e 796c 6379 0700 2d0c 002e
002f 0100 106a 6176 612f 6c61 6e67 2f4f
626a 6563 7401 0013 6a61 7661 2f6c 616e
672f 436c 6f6e 6561 626c 6501 0010 6a61
7661 2f6c 616e 672f 5379 7374 656d 0100
036f 7574 0100 154c 6a61 7661 2f69 6f2f
5072 696e 7453 7472 6561 6d3b 0100 136a
6176 612f 696f 2f50 7269 6e74 5374 7265
616d 0100 0770 7269 6e74 6c6e 0100 1528
4c6a 6176 612f 6c61 6e67 2f53 7472 696e
673b 2956 0021 0005 0008 0001 0009 0002
0019 000a 000b 0001 000c 0000 0002 0006
0002 000d 000e 0000 0004 0001 000f 0010
0001 0011 0000 002f 0001 0001 0000 0005
2ab7 0001 b100 0000 0200 1200 0000 0600
0100 0000 0600 1300 0000 0c00 0100 0000
0500 1400 1500 0000 0100 1600 1000 0100
1100 0000 3900 0300 0100 0000 0b2a 59b4
0002 0460 b500 02b1 0000 0002 0012 0000
000a 0002 0000 000c 000a 000d 0013 0000
000c 0001 0000 000b 0014 0015 0000 0001
0017 0018 0001 0011 0000 00ae 0001 0005
0000 0018 043c 1b3d 063c 1cac 4d05 3c1b
3e06 3c1d ac3a 0406 3c19 04bf 0004 0000
0004 0008 0003 0000 0004 0011 0000 0008
000d 0011 0000 0011 0013 0011 0000 0002
0012 0000 002a 000a 0000 0012 0002 0013
0004 0018 0006 0013 0008 0014 0009 0015
000b 0016 000d 0018 000f 0016 0011 0018
0013 0000 0034 0005 0002 0006 0019 000e
0001 0009 0008 001a 001b 0002 000b 0006
0019 000e 0001 0000 0018 0014 0015 0000
0015 0003 0019 000e 0001 0009 001c 0010
0001 0011 0000 0025 0002 0000 0000 0009
b200 0412 06b6 0007 b100 0000 0100 1200
0000 0a00 0200 0000 1d00 0800 1e00 0100
1d00 0000 0200 1e

Running the examples

public class ClassFileTest {

    @Test
    public void classfile() throws Exception {
        File file = new File("/path/to/TestClass.class");
        FileInputStream inputStream = new FileInputStream(file);
        ClassReader.analyze(inputStream);
    }
}

Output

magic = cafebabe
minorVersion = 0
majorVersion = 49
constantPoolCount = 48
cpInfo[1] = ConstantMethodRefInfo{classIndex=8, nameAndTypeIndex=31}
cpInfo[2] = ConstantFieldRefInfo{classIndex=5, nameAndTypeIndex=32}
cpInfo[3] = ConstantClassInfo{index=33}
cpInfo[4] = ConstantFieldRefInfo{classIndex=34, nameAndTypeIndex=35}
cpInfo[5] = ConstantClassInfo{index=36}
cpInfo[6] = ConstantClassInfo{index=37}
cpInfo[7] = ConstantMethodRefInfo{classIndex=38, nameAndTypeIndex=39}
cpInfo[8] = ConstantClassInfo{index=40}
cpInfo[9] = ConstantClassInfo{index=41}
cpInfo[10] = ConstantUtf8Info{bytesValue='TAG'}
cpInfo[11] = ConstantUtf8Info{bytesValue='Ljava/lang/String;'}
cpInfo[12] = ConstantUtf8Info{bytesValue='ConstantValue'}
cpInfo[13] = ConstantUtf8Info{bytesValue='num'}
cpInfo[14] = ConstantUtf8Info{bytesValue='I'}
cpInfo[15] = ConstantUtf8Info{bytesValue='<init>'}
cpInfo[16] = ConstantUtf8Info{bytesValue='()V'}
cpInfo[17] = ConstantUtf8Info{bytesValue='Code'}
cpInfo[18] = ConstantUtf8Info{bytesValue='LineNumberTable'}
cpInfo[19] = ConstantUtf8Info{bytesValue='LocalVariableTable'}
cpInfo[20] = ConstantUtf8Info{bytesValue='this'}
cpInfo[21] = ConstantUtf8Info{bytesValue='Lorg/tinylcy/TestClass;'}
cpInfo[22] = ConstantUtf8Info{bytesValue='inc'}
cpInfo[23] = ConstantUtf8Info{bytesValue='exception'}
cpInfo[24] = ConstantUtf8Info{bytesValue='()I'}
cpInfo[25] = ConstantUtf8Info{bytesValue='x'}
cpInfo[26] = ConstantUtf8Info{bytesValue='e'}
cpInfo[27] = ConstantUtf8Info{bytesValue='Ljava/lang/Exception;'}
cpInfo[28] = ConstantUtf8Info{bytesValue='showTag'}
cpInfo[29] = ConstantUtf8Info{bytesValue='SourceFile'}
cpInfo[30] = ConstantUtf8Info{bytesValue='TestClass.java'}
cpInfo[31] = ConstantNameAndTypeInfo{nameIndex=15, descriptorIndex=16}
cpInfo[32] = ConstantNameAndTypeInfo{nameIndex=13, descriptorIndex=14}
cpInfo[33] = ConstantUtf8Info{bytesValue='java/lang/Exception'}
cpInfo[34] = ConstantClassInfo{index=42}
cpInfo[35] = ConstantNameAndTypeInfo{nameIndex=43, descriptorIndex=44}
cpInfo[36] = ConstantUtf8Info{bytesValue='org/tinylcy/TestClass'}
cpInfo[37] = ConstantUtf8Info{bytesValue='tinylcy'}
cpInfo[38] = ConstantClassInfo{index=45}
cpInfo[39] = ConstantNameAndTypeInfo{nameIndex=46, descriptorIndex=47}
cpInfo[40] = ConstantUtf8Info{bytesValue='java/lang/Object'}
cpInfo[41] = ConstantUtf8Info{bytesValue='java/lang/Cloneable'}
cpInfo[42] = ConstantUtf8Info{bytesValue='java/lang/System'}
cpInfo[43] = ConstantUtf8Info{bytesValue='out'}
cpInfo[44] = ConstantUtf8Info{bytesValue='Ljava/io/PrintStream;'}
cpInfo[45] = ConstantUtf8Info{bytesValue='java/io/PrintStream'}
cpInfo[46] = ConstantUtf8Info{bytesValue='println'}
cpInfo[47] = ConstantUtf8Info{bytesValue='(Ljava/lang/String;)V'}
accessFlags = 21, public super 
thisClass = 5, this class name = org/tinylcy/TestClass
superClass = 8, super class name = java/lang/Object
interfacesCount = 1
interfaces[0] = 9, interface name = java/lang/Cloneable
fieldsCount = 2
fields[0] = FieldInfo{accessFlags=25: public static final , nameIndex=10 [name = TAG], descriptorIndex=11 [descriptor = Ljava/lang/String;], attributesCount=1, attributes=[]}
fields[1] = FieldInfo{accessFlags=2: private , nameIndex=13 [name = num], descriptorIndex=14 [descriptor = I], attributesCount=0, attributes=[]}
methodsCount = 4
methods[0] = MethodInfo{accessFlags=1: public , nameIndex=15 [name = <init>], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=47, maxStack=1, maxLocals=1, codeLength=5, code=[42, -73, 0, 1, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=6, lineNumberTableLength=1, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=6}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=12, localVariableTableLength=1}]}]}
methods[1] = MethodInfo{accessFlags=1: public , nameIndex=22 [name = inc], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=57, maxStack=3, maxLocals=1, codeLength=11, code=[42, 89, -76, 0, 2, 4, 96, -75, 0, 2, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=10, lineNumberTableLength=2, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=12}, LineNumberInfo{startPc=10, lineNumber=13}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=12, localVariableTableLength=1}]}]}
methods[2] = MethodInfo{accessFlags=1: public , nameIndex=23 [name = exception], descriptorIndex=24 [descriptor = ()I], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=174, maxStack=1, maxLocals=5, codeLength=24, code=[4, 60, 27, 61, 6, 60, 28, -84, 77, 5, 60, 27, 62, 6, 60, 29, -84, 58, 4, 6, 60, 25, 4, -65], exceptionTableLength=4, exceptionTable=[ExceptionInfo{startPc=0, endPc=4, handlerPc=8, catchType=3}, ExceptionInfo{startPc=0, endPc=4, handlerPc=17, catchType=0}, ExceptionInfo{startPc=8, endPc=13, handlerPc=17, catchType=0}, ExceptionInfo{startPc=17, endPc=19, handlerPc=17, catchType=0}], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=42, lineNumberTableLength=10, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=18}, LineNumberInfo{startPc=2, lineNumber=19}, LineNumberInfo{startPc=4, lineNumber=24}, LineNumberInfo{startPc=6, lineNumber=19}, LineNumberInfo{startPc=8, lineNumber=20}, LineNumberInfo{startPc=9, lineNumber=21}, LineNumberInfo{startPc=11, lineNumber=22}, LineNumberInfo{startPc=13, lineNumber=24}, LineNumberInfo{startPc=15, lineNumber=22}, LineNumberInfo{startPc=17, lineNumber=24}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=52, localVariableTableLength=5}]}]}
methods[3] = MethodInfo{accessFlags=9: public static , nameIndex=28 [name = showTag], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=37, maxStack=2, maxLocals=0, codeLength=9, code=[-78, 0, 4, 18, 6, -74, 0, 7, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=1, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=10, lineNumberTableLength=2, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=29}, LineNumberInfo{startPc=8, lineNumber=30}]}]}]}
attributesCount = 1
attributes[0] = SourceFile{attributeNameIndex=29 [attribute name = SourceFile], attributeLength=2, sourceFileIndex=30}

Bytes analysis

cafe babe : magic
0000 : minor version
0034 : major version

0030 : constant pool count
0a : tag
00 08 : class index
00 1f : nameAndType index
09 : tag
0005 : class index
0020 : nameAndType index
07 : tag
00 21 : index
09 : tag
0022 : class index
0023 : nameAndType index
07 : tag
00 24 : index
08 : tag
0025 : index
0a : tag
0026 : class index
0027 : nameAndType index
07 : tag
0028 : index
07 : tag
00 29 : index
01 : tag
0003 : length
5441 47 : bytes
01 : tag
0012 : length
4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b : bytes
01 : tag
00 0d : 13
43 6f6e 7374 616e 7456 616c 7565 : bytes
01 : tag
00 03 : length
6e 756d : bytes
01 : tag
00 01 : length
49 : bytes
01 : tag
00 06 : length
3c 696e 6974 3e : bytes
01 : tag
0003 : length
2829 56 : bytes
01 : tag
0004 : length
436f 6465 : bytes
01 : tag
00 0f : length
4c 696e 654e 756d 6265 7254 6162 6c65 : bytes
01 : tag
00 12 : length
4c 6f63 616c 5661 7269 6162 6c65 5461 626c 65 : bytes
01 : tag
0004 : length
7468 6973 : bytes
01 : tag
00 17 : length
4c 6f72 672f 7469 6e79 6c63 792f 5465 7374 436c 6173 733b : bytes
01 : tag
00 03 : length
69 6e63 : bytes
01 : tag
00 09 : length
65 7863 6570 7469 6f6e : bytes
01 : tag
00 03 : length
28 2949 : bytes
01 : tag
00 01 : length
78 : bytes
01 : tag
00 01 : length
65 : bytes
01 : tag
00 15 : length
4c 6a61 7661 2f6c 616e 672f 4578 6365 7074 696f 6e3b : bytes
01 : tag
00 07 : length
73 686f 7754 6167 : bytes
01 : tag
00 0a : length
53 6f75 7263 6546 696c 65 : bytes
01 : tag
000e : length
5465 7374 436c 6173 732e 6a61 7661 : byte
0c : tag
00 0f : name index
00 10 : descriptor index
0c : tag
000d : name index
000e : descriptor index
01 : tag
00 13 : length
6a 6176 612f 6c61 6e67 2f45 7863 6570 7469 6f6e : bytes
07 : tag
00 2a : index
0c : tag
002b : name index
002c : descriptor index
01 : tag
00 15 : length
6f 7267 2f74 696e 796c 6379 2f54 6573 7443 6c61 7373 : bytes
01 : tag
00 07 : length
74 696e 796c 6379 : bytes
07 : tag
00 2d : index
0c : tag
002e : name index
002f : descriptor index
01 : tag
00 10 : length
6a 6176 612f 6c61 6e67 2f4f 626a 6563 74 : bytes
01 : tag
0013 : length
6a61 7661 2f6c 616e 672f 436c 6f6e 6561 626c 65 : bytes
01 : tag
0010 : length
6a61 7661 2f6c 616e 672f 5379 7374 656d : bytes
01 : tag
00 03 : length
6f 7574 : bytes
01 : tag
00 15 : length
4c 6a61 7661 2f69 6f2f 5072 696e 7453 7472 6561 6d3b : bytes
01 : tag
00 13 : length
6a 6176 612f 696f 2f50 7269 6e74 5374 7265 616d : bytes
01 : tag
00 07 : length
70 7269 6e74 6c6e : bytes
01 : tag
00 15 : length
28 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 2956 bytes

0021 : access flags
0005 : this class
0008 : super class

0001 : interfaces count
0009 : interfaces

0002 : fields count
0019 : access flags
000a : name index
000b : descriptor index
0001 : attributes count
000c : attribute name index
0000 0002 : attribute length
0006 : constant value index
0002 : access flags
000d : name index
000e : descriptor index
0000 : attribute count

0004 : methods count
0001 : access flags
000f : name index
0010 : descriptor index
0001 : attributes count
0011 : attribute name index
0000 002f : attribute length
0001 : max stack
0001 : max locals
0000 0005 : code length
2ab7 0001 b1 : code
00 00 : exception table length
00 02 : attributes count
00 12 : attribute name index
00 0000 06 : attribute length
00 01 : line number table length
00 00 : start pc
00 06 : line number
00 13 : attribute name index
00 0000 0c : attribute length
00 01 : local variable table length
00 00 : start pc
00 05 : length
00 14 : name index
00 15 : descriptor index
00 00 : index
00 01 : access flags
00 16 : name index
00 10 : descriptor index
00 01 : attributes count
00 11 : attribute name index
00 0000 39 : attribute length
00 03 : max stack
00 01 : max locals
00 0000 0b : code length
2a 59b4 0002 0460 b500 02b1 : code
0000 : exception table length
0002 : attributes count
0012 : attribute name index
0000 000a : attribute length
0002 : line number table length
0000 : start pc
000c : line number
000a : start pc
000d : line number
0013 : attribute name index
0000 000c : attribute length
0001 : local variable table length
0000 : start pc
000b : length
0014 : name index
0015 : descriptor index
0000 : index
0001 : access flags
0017 : name index
0018 : descriptor index
0001 : attributes count
0011 : attribute name index
0000 00ae : attribute length
0001 : max stack
0005 : max locals
0000 0018 : code length
043c 1b3d 063c 1cac 4d05 3c1b 3e06 3c1d ac3a 0406 3c19 04bf : code
0004 : exception table length
0000 : start pc
0004 : end pc
0008 : handler pc
0003 : catch type
0000 : start pc
0004 : end pc
0011 : handler pc
0000 : catch type
0008 : start pc
000d : end pc
0011 : handler pc
0000 : catch type
0011 : start pc
0013 : end pc
0011 : handler pc
0000 : catch type
0002 : attributes count
0012 : attribute name index
0000 002a : attribute length
000a : line number table length
0000 : start pc
0012 : line number
0002 : start pc
0013 : line number
0004 : start pc
0018 : line number
0006 : start pc
0013 : line number
0008 : start pc
0014 : line number
0009 : start pc
0015 : line number
000b : start pc
0016 : line number
000d : start pc
0018 : line number
000f : start pc
0016 : line number
0011 : start pc
0018 : line number
0013 : attribute name index
0000 0034 : attribute length
0005 : local variable table length
0002 : start pc
0006 : length
0019 : name index
000e : descriptor index
0001 : index
0009 : start pc
0008 : length
001a : name index
001b : descriptor index
0002 : index
000b : start pc
0006 : length
0019 : name index
000e : descriptor index
0001 : index
0000 : start pc
0018 : length
0014 : name index
0015 : descriptor index
0000 : index
0015 : start pc
0003 : length
0019 : name index
000e : descriptor index
0001 : index
0009 : access flags
001c : name index
0010 : descriptor index
0001 : attributes count
0011 : attribute name index
0000 0025 : attribute length
0002 : max stack
0000 : max locals
0000 0009 : code length
b200 0412 06b6 0007 b1 : code
00 00 : exception table length
00 01 : attributes count
00 12 : attribute name index
00 0000 0a : attribute length
00 02 : line number table
00 00 : start pc
00 1d : line number
00 08 : start pc
00 1e : line number

00 01 : attributes count    
00 1d : attribute name index
00 0000 02 : attribute length
00 1e : source file index

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为什么要学JVM1、一切JAVA代码都运行在JVM之上,只有深入理解虚拟机才能写出更强大的代码,解决更深层次的问题。2、JVM是迈向高级工程师、架构师的必备技能,也是高薪、高职位的不二选择。3、同时,JVM又是各大软件公司笔试、面试的重中之重,据统计,头部的30家互利网公司,均将JVM作为笔试面试的内容之一。4、JVM内容庞大、并且复杂难学,通过视频学习是最快速的学习手段。课程介绍本课程包含11个大章节,总计102课时,无论是笔试、面试,还是日常工作,可以让您游刃有余。第1章 基础入门,从JVM是什么开始讲起,理解JDK、JRE、JVM的关系,java的编译流程和执行流程,让您轻松入门。第2章 字节码文件,深入剖析字节码文件的全部组成结构,以及javap和jbe可视化反解析工具的使用。第3章 类的加载、解释、编译,本章节带你深入理解类加载的分类、范围、双亲委托策略,自己手写类加载,理解字节码解释、即时编译、混合模式、热点代码检测、分层编译等核心知识。第4章 内存模型,本章节涵盖JVM内存模型的全部内容,程序计数、虚拟机栈、本地方法栈、方法区、永久代、元空间等全部内容。第5章 对象模型,本章节带你深入理解对象的创建过程、内存分配的方法、让你不再稀里糊涂。第6章 GC基础,本章节是垃圾回收的入门章节,带你了解GC回收的标准是什么,什么是可达性分析、安全点、安全区,四种引用类型的使用和区别等等。第7章 GC算法与收集,本章节是垃圾回收的重点,掌握各种垃圾回收算法,分代收集策略,7种垃圾回收的原理和使用,垃圾回收的组合及分代收集等。第8章 GC日志详解,各种垃圾回收的日志都是不同的,怎么样读懂各种垃圾回收日志就是本章节的内容。第9章 性能监控与故障排除,本章节实战学习jcmd、jmx、jconsul、jvisualvm、JMC、jps、jstatd、jmap、jstack、jinfo、jprofile、jhat总计12种性能监控和故障排查工具的使用。第10章 阿里巴巴Arthas在线诊断工具,这是一个特别小惊喜,教您怎样使用当前最火热的arthas调优工具,在线诊断各种JVM问题。第11章 故障排除,本章会使用实际案例讲解单点故障、高并发和垃圾回收导致的CPU过高的问题,怎样排查和解决它们。课程资料课程附带配套项目源码2个159页高清PDF理论篇课件1份89页高清PDF实战篇课件1份Unsafe源码PDF课件1份class_stats字段说明PDF文件1份jcmd Thread.print解析说明文件1份JProfiler内存工具说明文件1份字节码可视化解析工具1份GC日志可视化工具1份命令行工具cmder 1份学习方法理论篇部分推荐每天学习2课时,可以在公交地铁上用手机进行学习。实战篇部分推荐对照视频,使用配套源码,一边练习一遍学习。课程内容较多,不要一次性学太多,而是要循序渐进,坚持学习。      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值