浅入虚拟机(一)

class文件&dex文件

Posted by Cc1over on November 23, 2018

class文件&dex文件

class文件结构与解析

文件结构

  • 一种8位字节的二进制流文件

  • 各个数据按顺序紧密排序,无间隙

    这样做的好处就是可以减少class文件的体积,提高JVM加载class文件效率

  • 每个类或接口都单独占据一个class文件

    这样就可以做到每个类或接口都可以独立管理自身的内容,无需相互交叉

class文件中的各个数据项

  • magic

    无符号4字节,用来表示class文件的开头,加密段,给虚拟机用来判断当前的 class文件是否被串改过

  • minor_version class文件最小可以被哪个版本的jdk所加载,也就是最小适配的jdk

  • major_version 表示我们当前class文件是由哪个版本的jdk生成的

  • constant_pool_count class文件中常量池的数量,通常只有一个常量池

  • constant_pool 代表常量池,类型为cp_info(结构体类型), 常量池中主要包含的内容:

    • CONSTANT_Integer_info:存储class文件中的int类型
    • CONSTANT_Long_info:存储class文件中的long类型
    • CONSTANT_String_info:存储class文件中的string类型, 它们分别存储字节码中的int、long、string类型,当然还有CONSTANT_Short_info、CONSTANT_Float_info等
    • CONSTANT_Class_info:记录类中相关的信息、不仅记录了当前类的信息,还记录了引用到的一些类的信息
    • CONSTANT_Fieldref_info:记录类中Field相关的信息
    • CONSTANT_Methodref_info:记录类中Method相关的信息 Ps:这三个里面存储的并不是真正的内容,都是一些索引,这些索引指向的又是CONSTANT_String_info等<
  • access_flags 表示class文件的作用域标志

    access_flags的取值范围和相应含义

    • ACC_PUBLIC:取值为0x0001

    • ACC_FINAL::取值为0x0010

    • ACC_SUPER:取值为0x0020,用于确定该Class文件里面的invokespecial指令使用的是哪一种执行语义。目前Java虚拟机的编译器都应当设置这个标志。ACC_SUPER标记是为了向后兼容旧编译器编译的Class文件而存在的,在JDK1.0.2版本以前的编译器产生的Class文件中,access_flag里面没有ACC_SUPER标志。同时,JDK1.0.2前的Java虚拟机遇到ACC_SUPER标记会自动忽略它

    • ACC_INTERFACE:取值为0x0200,表示是接口

    • ACC_ABSTRACT:取值为0x0400

    • ACC_SYNTHETIC:取值为0x1000, 表示并非Java源码生成的字节码

    • ACC_ANOTATION:0x2000,表示是注解

    • ACC_ENUM:取值为0x4000,表示是枚举

  • this_class this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。

  • super_class super_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口的直接父类。只有Object类才没有直接父类,此时该索引值为0。并且父类不能是final类型。接口的父类都是Object类。

  • interfaces_count 当前class文件直接实现的接口数量。

  • interfaces 当前class文件直接实现的接口,只记录直接实现的,不会记录间接实现的。

  • fields_count class文件中成员变量的数量。

  • fields class文件中所有的成员变量,field_info类型的结构体,该结构体中主要包含了每个成员变量的name、所属的类以及类型。

  • methods_count 记录class文件中方法的数量。

  • methods 记录class文件中所有的方法,类型为method_info结构体类型,主要包含了方法的名字、类型、access_flags等信息。

  • attribute_count 记录了class文件属性的数量。

  • attributes 记录class文件的一些属性,除去上面的一些信息剩下的都包含在attributes中,比如 说注解。

class文件弊端

  • 内存占用大,不适合移动端
  • 堆栈的加栈模式,加载速度慢
  • 文件IO操作多,类查找慢

dex文件结构与解析

文件结构

  • 一种8位字节的二进制流文件
  • 各个数据按顺序紧密的排列,无间隙
  • 整个应用中所有Java源文件都放在一个dex中

文件头

  • header

    记录dex文件的信息,以及所有字段大致的分布

索引区

  • string_ids

    字符串数据索引,记录了整个应用中所有的字符串,包括构造方法的字符串,类名字符串,用到的变量和方法的字符串

  • type_ids

    类似数据索引,记录了每个类型的字符串索引

  • proto_ids

    原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表

  • field_ids

    字段数据索引,记录了所属类,类型以及方法名

  • method_ids

    类方法索引,记录方法所属类名,方法声明以及方法名等信息

数据区

  • class_defs

    类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量

  • data

    数据区,保存了各个类的真实数据,也就是上面索引区指向的地方,通过索引到数据区就可以找到真实的值

  • link_data

    连接数据区,就是连接动态链接库so库的指向

对比与总结

从宏观上两种字节码文件是一样的,都是二进制无缝隙的文件格式,但是.class文件就是单独的结构体,因此存在许多的多余的信息,而.dex就划分成三个区,这三个区直接存储了整个project中所有源文件,所以当源文件越来越多的时候,.dex可以复用的地方就变多了,极大地减少.dex文件的体积,从而也提高了效率。

参考资料:

  • https://www.jianshu.com/p/5f9a989d3082
  • https://www.jianshu.com/p/f7f0a712ddfe