在学习java虚拟机之前,我们有必要先来了解下下class文件与dex文件。相比大家对这两文件都耳熟能详,但是对于初学者来说却是"听起声而不见其人"。下面我们就来了解下。首先我们先来对他们有个总体的概念:
这就是两者大致的作用与概念。下面我们来分别了解下。
图片.png
为了更好的理解与回顾基础,我们在走一遍2.这个流程。
public class Hellow {
public static void main(String args[]){
System.out.println("Hellow Android!\n");
}
}
javac Hellow.java
通过在命令行输入这段命令。我们就可以生成Hellow.class文件。这时我们就可以通过java命令:
java Hellow
后接我们的类名来运行这个.class文件来执行我们的代码。最后输出入下:
图片.png
现在我们回头看看开头的总结图。就更加明了了.class文件是什么了。
下面我们就来了解下class文件结构类型:
clipboard.png
这张图就是一个.class文件包含的所有类型。这里面比较中的要的就常量池。我们的主要内容都包含在其中。那么constant_pool又有哪些类型呢?我们来简单列举下: 简单类型(基础数据类型常量):
图片.png 此图为打开二进制.class文件的结构图。从图中可以看到,一个.class文件正是包含上面我们所列举出来的类型。其中常量池(constant_pool)所占最多,而他的类型(Comment)可以看到正是我们列举出来的。我们打开看下:
图片.png 我们以cp_info(结构体类型) constant_pool(常量池)为例。 它里面分别包含tag(标记) class_index(表明方法所属那个类) name_and_type_index(方法名与类型) 最后根据索引可以找到他具体的内容。这里我们只需大概有个了解,更详细讲解查考Class文件内容解析
基于class的缺点,在Android平台移动设备上我们运行在Dalvik即为dex文件。他的作用为记录整个工程所有类文件的的信息。记住是整个工程。下面我们简单了解下如何生成 :
图片.png
dex文件结构:
可以看到他与class文件只有最后一点不同。 下面我们来具体看下。
dex文件结构:
图片.png
从图中我们看到分三个区。文件头:描述了dex文件的基本信息(所有字段大致的分布等);索引区:包含所有相关信息的索引;数据区:索引所指向的位置即在数据区存储,即索引区尽量位置,数据区记录位置所指向的具体数据。这里面的链接数据区即为我们的动态链接库.so文件。下面我们分别对3本分讲解。
dex文件头:
图片.png
总结: dex文件头记录dex文件大小以及各个区段的起始位置和长度(偏移量)
索引区:
图片.png
从这幅图中我们可以看到。第一行为头文件,以ids为结尾都是索引区,索引区所指引的值就是value位置中的值。里面包含了所有类的方法,类,以及常量等索引以及集体的数据。
图片.png 在class文件越来越多的时候 dex文件的3大区都不会增加。而.class文件会随着文件增多,每个文件的结构又独立,所以一定会产生很多冗余重复数据。
理解JVM我们先来看下他的结构:
图片.png
详细结构:
图片.png
2个图表达的含义是一样的。
从图中可以分为三部分。第一部分类加载器子系统将class文件进行加载,第二部分类加载器将加载后class字节码数据存放在内存空间,JVM将内存空间分成5部分,同时我们的垃圾回收机制(gc)也是回收这部分的内存占用。第三部分比较底层,是与一些系统CPU交互等。所以第三部分我们占不做分析。
这部分主要就是讲.java源文件转化为.class字节码文件。如何生成前面已经提过。具体细节如下:
clipboard.png
这些生成都是javac来完成的 javac就是java编译器
类加载指将类的字节码文件(.class)中的二进制数据读入内存,将其放在运行时数据区的方法区内,然后在堆上创建java.lang.Class对象,封装类在方法区内的数据结构类装载器子系统负责查找并装载类型信息。其实Java虚拟机有两种类装载器:系统装载器(前两个)和用户自定义装载器(后两个)。前者是Java虚拟机实现的一部分,后者则是Java程序的一部分。
clipboard.png
类加载指将类的字节码文件(.class)中的二进制数据读入内存,将其放在运行时数据区的方法区内,然后在堆上创建java.lang.Class对象,封装类在方法区内的数据结构。和其它对象一样,用户自定义的类装载器以及Class类的实例放在内存中的堆区,而装载的类型信息则位于方法区。
总结: 1和2加载器是加载加载jdk相关的class文件。3是加载应用用到的class文件,4是我们自定义类加载器,可以加载指定的class文件。
类加载器除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及解析符号引用。这些动作还需要按照以下顺序进行:
image
这部分是整合JVM的核心,也是GC垃圾回收的的主要部分,所以单独在下一篇讲解。
类加载器将字节码载入内存之后,执行引擎以Java字节码指令为单元,读取Java字节码。问题是,现在的java字节码机器是读不懂的,因此还必须想办法将字节码转化成平台相关的机器码。这个过程可以由解释器来执行,也可以有即时编译器(JIT Compiler)来完成。
image
优秀文章推荐(本文部分参考) Java虚拟机工作原理 理解Java虚拟机体系结构 Java虚拟机工作原理详解 书籍:《深入理解java虚拟机》(有需要PDF请留言,不过希望大家支持正版)