虚拟机执行子系统
一、虚拟机类加载机制
1.概述
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接 使用的Java类型,这就是虚拟机的类加载机制。
JAVA中类型的加载和连接过程都是在程序运行期间完成的,Java中动态扩展的特性依赖运行期加载。
约定
实际情况中,每个Class文件都有可能代表Java语言中的一个类或接口
Class文件,不是指磁盘中的某个文件,而是指一串二进制的字节流。
2.类加载的时机
- 生命周期:类从被加载到虚拟机内存中开始到卸载除内存为止,生命周期包括:加载,验证,准备,初始化,使用和卸载。
- 注意:加载、验证、准备、初始化和卸载顺序是确定的,类的加载过程必须按照这些顺序开始;解析阶段不一定,某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定(动态绑定)。
初始化操作时机
- 使用new关键字实例化对象时,读取或设置一个类的静态字段(被final修饰、以及在编译器吧结果放入常量池的静态字段外)时,以及调用一个类的静态方法的时候。
- 对类进行反射调用时,在没有初始化情况下,需要先出发初始化。
- 初始化一个类时候,如果父类没有进行初始化,先触发父类初始化。
- 虚拟机启动时,用户需要制定一个要执行的主类(包含main方法的那个类),虚拟机会先初始化那个主类。
加载
作用:
- 通过一个类的全限定名来获取此类的二进制字节流。
- 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构。
- 在java堆中生成一个代表此类的java.lang.Class对象,作为方法区的这些数据的访问入口。
获取类的全限定名的方式:
获取一个类的二进制字节流方式有很多种,不只是我们认为的从Class文件中获取,只要有全限定名就可以。
- 从zip包中获取,当然jar,ear,war等同理;
- 从网络中获取,典型应用就是Applet;
- 运行时计算生成,典型应用就是动态代理技术,java.lang .reflect.Proxy 包;
- 其他文件生成,Jsp……
验证
用途:确保Class文件的字节流中包括信息符合当前虚拟机的要求,并且不危害虚拟机
文件格式验证, 元数据验证,字节码验证,符号引用验证
准备
是着呢格式为类变量(static
修饰的变量)分配内存并设置了变量初始值的阶段
解析
是虚拟机将常量池内的符号引用替换为直接引用的过程。
初始化
初始化时类加载过程的最后一步,在本阶段,才真真正正开始执行类中定义的Java程序代码(字节码)
,已经被赋过系统要求的初始值会被初始化为程序制定的变量和其他资源。
用途:
3.类加载器
类加载器用来实现,通过一个类的全限定名来获取描述此类的二进制字节流操作,这个动作在java虚拟机外部实现,以便由程序自己决定如何去获取所需要的类。
用途:
- 实现类的加载动作。
- 确定这个类的唯一性(比较类的相等)
常用的类加载器
启动类加载器(加载自身包),扩展类加载器(加载引入包),应用程序类加载器(加载类)
双亲委派模型
工作过程:一个类加载器收到类加载的请求,首先不会自己尝试加载类,而是去交给自己的弗雷去完成,所有的加载请求都会被传送到顶层的启动类加载器,只有当父加载器反馈自己无法完成加载时,子类才会尝试去加载。
优势:确保系统中基础类不会被重复加载。
缺点:性能问题
spring框架重写了类加载器破坏了双亲委派模型,提高本身的加载速度。