第三部分 虚拟机执行子系统
第6章 类文件结构
//实现语言无关性的基础仍然是虚拟机和字节码存储格式,使用Java编译器可以把Java代码编译为存储字节码的Class文件,使用JRuby等其他语言的编译器一样可以把程序代码编译成Class文件,虚拟机并不关心Class的来源是什么语言,只要它符合Class文件应有的结构就可以在Java虚拟机中运行。
1.Class类文件的结构
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件之中,中间没有分隔符。
Class文件格式采用一种类似于C语言结构体的伪结构来存储,只有两种数据类型:无符号数和表。
每个Class文件的头4个字节成为魔数,唯一作用是用于确定这个文件是否为一个能被虚拟机接受的Class文件。
主次版本号之后的是常量池入口,常量池是Class文件结构中与其他项目关联最多的数据类型。主要存放两大类常量,即字面量(Literal)和符号引用(Symbolic References)。
第7章 虚拟机类加载机制
//代码编译的结果是从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步。
在Class文件中描述的各种信息,被加载到虚拟机中之后才能被运行和使用。而虚拟机是如何加载class文件,class文件中的信息进入到虚拟机后会发生什么变化?
虚拟机读取class文件,把描述类的数据从class文件加载到内存中,并对数据进行校验,转换解析和初始化,然后形成可以被虚拟机直接使用操作的Java类型,即虚拟机的类加载机制。
//Java中天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。
1.类加载的时机
类从被加载到虚拟机内存中开始,到卸载出内存为止。整个生命周期包括七个阶段。
加载、验证、准备、解析、初始化、使用和卸载七个阶段。
验证、准备和解析统称为连接(Linking)。
2.类加载的过程
2.1 加载阶段
加载阶段,特别是加载时获取类的二进制字节流的动作,是开发期可控性最强的阶段,因为既可以使用系统的类加载器,也可以自定义类加载器实现,并且通过自定义类加载器控制字节流的获取方式。
2.2 验证阶段
确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
2.3 准备阶段
正式为类变量分配内存并设置类变量初始值,这些内存都将在方法区中进行分配。
2.4 解析阶段
虚拟机将常量池内的符号引用替换为直接引用的过程。
2.5 初始化阶段
初始化阶段,才真正开始执行类中定义的Java程序代码,即字节码。
3.类加载器
//类加载阶段的"通过一个类的全限定名来获取描述此类的二进制字节流"这个动作被放到虚拟机外部实现,
//即应用程序自己控制获取,实现这个动作的代码模块被称为"类加载器"。
类加载器在类层次划分,OSGi,热部署,代码加密等领域都应用到。
3.1 类与类加载器
3.2 双亲委派模型
从虚拟机的角度,存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类使用C++语言实现,是虚拟机自身的一部分,另一种是所有其他的类加载器,全部继承自抽象类java.lang.ClassLoader。
双亲委派模型的工作过程,即一个类加载器收到类加载的请求,首先会委派给父类加载器去完成,所有的加载请求都传送到顶层的启动类加载器,如果父类加载器反馈无法完成加载请求,会继续交由子类加载。
这样加载的好处是Java类随着它的类加载器拥有了带优先级的层次关系,避免了出现一个类加载多次。
第8章 虚拟机字节码执行引擎
1.运行时栈帧结构
2.方法调用
3.基于栈的字节码解释执行引擎
第9章 类加载及执行子系统的案例与实战
//在Class文件格式与执行引擎这部分里,主要是由虚拟机直接控制的行为,能通过程序进行操作的,主要是字节码生成与类加载器这两部分。
1.案例分析
Tomcat:正统的类加载器结构
主流的Java Web服务器,如Tomcat、Weblogic等都实现了自己定义的类加载器。
一个功能完备的Web服务器,要解决下面的问题:
部署在同一个服务器上的多个Web应用程序使用的Java类库既可以实现相互隔离,又可以互相共享。