Change Dir

先知cd——热爱生活是一切艺术的开始

统计

留言簿(18)

积分与排名

“牛”们的博客

各个公司技术

我的链接

淘宝技术

阅读排行榜

评论排行榜

JVM学习笔记(1)——java class

例子主要是《深入jvm》中的例子,class文件是其中的act.class,java源文件是:

class Act {

    public static void doMathForever() {
        int i = 0;
        for (;;) {
            i += 1;
            i *= 2;
        }
    }
}

class文件hex形式:

CA FE BA BE 00 03 00 2D  00 11 07 00 07 07 00 10
0A 00 02 00 04 0C 00 06  00 05 01 00 03 28 29 56
01 00 06 3C 69 6E 69 74  3E 01 00 03 41 63 74 01
00 08 41 63 74 2E 6A 61  76 61 01 00 04 43 6F 64
65 01 00 0D 43 6F 6E 73  74 61 6E 74 56 61 6C 75
65 01 00 0A 45 78 63 65  70 74 69 6F 6E 73 01 00
0F 4C 69 6E 65 4E 75 6D  62 65 72 54 61 62 6C 65
01 00 0E 4C 6F 63 61 6C  56 61 72 69 61 62 6C 65
73 01 00 0A 53 6F 75 72  63 65 46 69 6C 65 01 00
0D 64 6F 4D 61 74 68 46  6F 72 65 76 65 72 01 00
10 6A 61 76 61 2F 6C 61  6E 67 2F 4F 62 6A 65 63
74 00 20 00 01 00 02 00  00 00 00 00 02 00 09 00
0F 00 05 00 01 00 09 00  00 00 30 00 02 00 01 00
00 00 0C 03 3B 84 00 01  1A 05 68 3B A7 FF F9 00
00 00 01 00 0C 00 00 00  12 00 04 00 00 00 05 00
02 00 07 00 05 00 08 00  09 00 06 00 00 00 06 00
05 00 01 00 09 00 00 00  1D 00 01 00 01 00 00 00
05 2A B7 00 03 B1 00 00  00 01 00 0C 00 00 00 06
00 01 00 00 00 02 00 01  00 0E 00 00 00 02 00 08

  1. java的class文件是8位二进制流,数据项按顺序存放,无间隔,占多字节的数据项以高位在前的顺序分几个字节存放;
  2. java class基本类型:u1,u2,u4,u8,分别对应:1,2,4,8字节的无符号类型;
  3. java class file表格展示:(太大了,来个url自己看吧,wikipedia
  4. 表项详解:1)magic(魔数):说白了就是cafebabe,本来java就是咖啡嘛,这4个字节用来区分是否是java的class文件,有则是;2)minor_version&major_version:两个字节的minor和两个字节的major,以上为例就是minor:3,major:2D(JDK 1.1);3)再之后就是常量池了,2个字节表示constant_pool_count,本例是17,表示class文件中常量池中的项数(比实际的大1),接着就是常量池,连续的constant_pool_count-1个字节存储常量池各个入口,常量池入口项解释见本文第5条笔记;4)在之后的是access_flags:2个字节表示访问类型,是类还是接口,是public还是private,abstract或者final等等,标志位具体定义见本文第6条笔记,本例是00 20,表示老版本ACC_SUPER;5)之后是this_class,这是2字节的一个对常量池的索引,本例是00 01,即本例的自身类叫做Act;6)之后就是super_class,也是一个2字节常量池索引,指向父类的名字, 本例是00 02,即java.lang.Object;7)interface_count和interfaces:interface_count指出本文件有多少直接实现或者由接口扩展的父接口的数量,本例没有,故为00 00,之后是interfaces的具体内容,实际的项数就是之前的interface_count数,因为interface_count=0,所以本例的interfaces就没有值;8)接下来是fields_count和fields:对本类所声明的字段的描述,首先是个2字节的count,本例是00 00,所以后续也没有fields的项;9)再之后就是methods_count和methods了,count是一个2字节数据,本例的method_count是00 02,这个count只表示在类或接口中显式定义的方法,继承的方法不计数,count后是method_info的表,包含方法的一些信息如方法名、描述符等,本例中00 09表明方法是public(01)&static(08),00 0F是方法名的常量池入口,即常量池的第15项doMathForever,再下来00 05是方法描述符常量池入口,即常量池第5项:()V,然后00 01是属性表的count数,表示1项属性,接下来是00 09表示属性表的常量池入口即常量池第9项Code,接下来的4个字节00 00 00 30表示code属性长度:48字节,接着00 02是操作数最大数,然后00 01是局部变量存储长度,这里方法里只有一个变量i,所以是1,然后00 00 00 0c是code字节码长度12,然后的12个字节就是字节码code了,再后的00 00是异常数,之后异常栈数是0,跳过,就是00 01的属性数,然后00 0C指向常量池的第12项即LineNumberTable,这是一个code属性,之后的00 00 00 12是属性长度,再后的00 04是line_number_info表的项数,接下来的4项(每项4字节)表示line_number_info,00 00 表示代码偏移量,00 05表示代码行号,后面的类似;10)最后是attributes_count和attributes,表明了类的属性,属性比较特殊,jvm定义了两种属性:SourceCode和InnerClass。
  5. 常量池各个标志解读(来源wikipedia)image ,这里详解一下本例中的常量池,常量池是
    cp_info
           {
               tag;
               info[];
           }
    类似这样的结构,先有一个无符号byte作为tag标志,对应表格中的数据,额外的info字节数组存储对应的数据index.
    我以表格的形式列出常量池的所有数据,应该算一目了然了吧:
  6. 常量index 标志 标志内容 字节 具体数据 实际含义
    1 07 00 07 2 class reference 常量池第7项是该class的内容
    2 07 00 10 2 class reference 常量池第16项是该class的内容
    3 0A 00 02 00 04 4 method ref 两个index,前两个字节表示池内的class索引位置,后两个字节是名字和类型描述
    4 0C 00 06 00 05 4 name & type 就是第3项方法指向的名字和类型的index
    5 01 00 03 2+x x个utf-8字符,此处x=3 实际值:()V,表示type(第三项方法的类型,具体含义参见描述符定义)
    6 01 00 06 2+x x=6 实际值:<init>,表示name(第三项方法的名字)
    7 01 00 03 2+x x=3 实际值:Act,第一项指向的具体字符内容
    8 01 00 08 2+x x=8 实际值:Act.java,
    9 01 00 04 2+x x=4 实际值:Code
    10 01 00 0D 2+x x=0D=13 实际值:ConstantValue
    11 01 00 0A 2+x x=0A=10 实际值:Exceptions
    12 01 00 0F 2+x x=0F=15 实际值:LineNumberTable
    13 01 00 0E 2+x x=0E=14 实际值:LocalVariable
    14 01 00 0A 2+x x=0A=10 实际值:SourceFile
    15 01 00 0D 2+x x=0D=13 实际值:doMathForever
    16 01 00 10 2+x x=10=16 实际值:java/lang/Object
  7. 访问标志,待完善,这里有详细的spec
  8. 描述符的完整定义:非终结符是正常体,终结符是粗体,*号表示之前符号出现0或多次
    FieldDescriptor FieldType
    ComponentType FieldType
    FieldType BaseType,ObjectType,ArrayType
    BaseType B,C,D,F,I,J,S,Z
    ObjectType L<classname>;
    ArrayType [ComponentType
    MethodDescriptor (ParameterDescriptor*)ReturnDescriptor
    ParameterDescriptor FieldType
    ReturnDescriptor FieldType,V
  9. 基本类型终结符:V代表void
    终结符 类型
    B byte
    C char
    D double
    F float
    I int
    J long
    S short
    Z boolean
  10. 一些描述符的例子:
    描述符 字段或方法声明
    I int a;
    [[J long[][] b;
    [Ljava/lang/Object; java.lang.Object[] c;
    Ljava/util/HashMap; java.util.HashMap map;
    [[[Z boolean[][][] ok;
    ()I int m1();
    ()Ljava/lang/String; String m2();
    ([Ljava/lang/String;)V void main(String[] args);
    ()V void m3();
    (JI)V void m4(long a,int b);
    (Z[Ljava/lang/String;II)Z boolean m5(boolean a,String[] b,int c, int d);
    ([BII)I int m6(byte[] a,int b,int c);
  11. 声明字段时的字段表field_info:
    类型 名称 数量 含义
    u2 access_flags 1 访问标志
    u2 name_index 1 字段简单名称的常量池utf8_info入口索引
    u2 descriptor_index 1 字段描述符的常量池utf8_info入口索引
    u2 attributes_count 1 attribute_info表的项数
    attribute_info attributes attributes_count 字段属性:ConstantValue, Deprecated, Synthetic(JVM规范)
  12. field_info中的access_flags标志含义:
    标志名 含义 使用范围
    ACC_PUBLIC 0x0001 public 类和接口
    ACC_PRIVATE 0x0002 private
    ACC_PROTECTED 0x0004 protected
    ACC_STATIC 0x0008 static 类和接口
    ACC_FINAL 0x0010 final 类和接口
    ACC_VOLATILE 0x0040 volatile
    ACC_TRANSIENT 0x0080 transient
  13. 声明方法时的方法表method_info:
    类型 名称 数量 含义
    u2 access_flags 1 访问修饰符
    u2 name_index 1 方法简单名称的常量池入口
    u2 descriptor_index 1 方法描述符的常量池入口
    u2 attributes_count 1 属性表的项数
    attribute_info attributes attributes_count 方法属性:Code,Deprecated, Exceptions和Synthetic(JVM规范)
  14. method_info表中的访问标志对应含义:值得说明的是接口的方法一定是public和abstract的,接口初始化方法可以用strictFP
    标志名 含义 使用范围
    ACC_PUBLIC 0x0001 public 类和接口
    ACC_PRIVATE 0x0002 private
    ACC_PROTECTED 0x0004 protected
    ACC_STATIC 0x0008 static
    ACC_FINAL 0x0010 final
    ACC_SYNCHRONIZED 0x0020 synchronized
    ACC_NATIVE 0x0100 native
    ACC_ABSTRACT 0x0400 abstract 类和接口
    ACC_STRICT 0x0800 strictFP 类和接口的<clinit>方法
  15. 类和接口的初始化方法(<clinit>)只有JVM可以直接调用,永远不会被java字节码直接调用。
  16. JVM规范定义的所有属性:
    属性名 使用者 描述
    Code method_info 方法的字节码和其他数据
    ConstantValue field_info final变量的值
    Deprecated field_info,method_info 字段或方法被禁用的指示符
    Exceptions method_info 方法可能抛出的可被检测的异常
    InnerClasses ClassFile 内部、外部类的列表
    LineNumberTable Code_attribute 方法的行号与字节码的映射
    LocalVariableTable Code_attribute 方法的局部变量的描述
    SourceFile ClassFile 源文件名
    Synthetic field_info,method_info 编译器产生的字段或者方法的指示符
  17. code属性的表code_attribute:
    类型 名称 数量 含义
    u2 attribute_name_index 1 包含“Code”的常量池入口
    u4 attribute_length 1 去除起始6个字节后的code属性长度
    u2 max_stack 1 方法执行任意时刻,该方法操作数栈的最大长度(以字为单位)
    u2 max_locals 1 方法局部变量需要的存储空间长度(以字为单位)
    u4 code_length 1 该方法字节码流的长度
    u1 code code_length  
    u2 exception_table_length 1 异常表项数
    exception_info exception_table exception_table_length 异常表
    u2 attributes_count 1 属性数
    attribute_info attributes attributes_count code属性:LineNumberTable和LocalVariableTable(JVM规范)
  18. 异常表excption_info:
    类型 名称 数量 含义
    u2 start_pc 1 代码数组起始处到异常处理器起始处的代码偏移量
    u2 end_pc 1 代码数组起始处到异常处理器结束后的一个字节的偏移量
    u2 handler_pc 1 代码数组起始处跳转到异常处理器的第一条指令的偏移量
    u2 catch_type 1 异常处理器捕获的异常类型的Class_info常量池入口,如果为0则表示处理finally子句,即处理所有异常
  19. constantValue属性:各种基础类型加字符串类型的常量池入口查找,结构很简单,这里就不列出了。
  20. LineNumberTable属性建立了方法字节码流便宜量和源代码行号之间的映射关系:
    类型 名称 数量 含义
    u2 attribute_name_index 1 包含“LineNumberTable”的常量池入口
    u4 attribute_length 1 去除起始6字节后的属性长度
    u2 line_number_table_length 1 line_number_info表长度
    line_number_info line_number_table line_number_
    table_length
    属性表
  21. line_number_info表很简单,就两个项:u2的start_pc给出新行开始时代码数组的偏移量,u2的line_number给出了从start_pc开始的行号。

 

这次就到这里。to be continued...

posted on 2012-09-17 16:38 changedi 阅读(501) 评论(0)  编辑  收藏 所属分类: Java技术


只有注册用户登录后才能发表评论。


网站导航: