虚拟机类加载机制

来源:互联网 发布:三体读后感知乎 编辑:程序博客网 时间:2024/06/08 15:12

1、类加载时机

类从被加载到被卸载,经历了加载->验证->准备->解析->初始化->使用->卸载 7个阶段。其中验证、准备、解析统称为连接
这里写图片描述

加载、验证、准备、初始化、卸载的顺序是固定不变的。而解析在某些情况下可能在初始化之后才开始,这是为了支持java的运行时绑定机制。

遇到以下条件,将立即对类初始化:
①遇到new(使用new实例化对象)、putstatic/getstatic(读写一个静态变量)、invokestatic(调用静态方法)
②使用java.lang.reflect包的方法对类进行反射调用,类如果没有被初始化过,将首先被初始化
③当初始化一个类时,其父类没有初始化过,则先对其父类初始化
④虚拟机启动时,会先初始化包含main()方法的类
⑤当使用java1.7的动态语言支持时,一个java.lang.invoke.MethodHandle实例的解析结果有REF_getStatic/REF_putStatic/REF_invokeStatic的方法句柄,并且这个句柄所对应的类没有初始化,则先初始化这个类

2、类加载过程

2.1 加载

加载阶段,虚拟机需要完成3个动作:
通过一个类的全限定名来获取定义此类的二进制流
将字节流的静态存储结构转化为运行时数据结构
在内存中生成一个代表这个类的class对象,作为各种数据结构的访问入口

二进制流可以从zip包、网络、数据库等中获取。可以自定义加载器类通过自己的方式加载二进制流

2.2 验证

确保class文件字节流中的信息符合当前虚拟机的要求,并且不会危害到虚拟机本身

2.3 准备

准备阶段正式为类变量(全局静态变量)分配内存并初始化,变量的内存都在方法区中分配。
通常的情况 例如public static int value = 123;
此时准备阶段,value的值为0
但是public static final int value = 123;
编译时javac会为value生成ConstantValue属性,即准备阶段value的值就是123

2.4 解析

解析是将常量池内的符号引用替换为直接引用的过程。符号引用就是常量池中CONSTANT_Class_info/CONSTANT_Method_info等字面值。直接引用就是直接指向目标的指针、句柄。
个人理解就是对符号引用做映射,可以通过地址直接找到类名/方法名

2.5 初始化

①初始化阶段首先执行<clinit>(),<clinit>()是由编译器自动收集类中所有类变量的赋值动作和静态代码块的语句合并产生的。
静态代码块中只能访问定义在代码块之前的变量。定义在代码块之后的只能赋值,不能访问。
②父类的<clinit>()优先于子类执行
③如果类或接口没有静态代码块或者类变量的赋值操作,则不需要<clinit>()
④执行接口的<clinit>不需要执行父接口的<clinit>,除非用到了父接口的类变量。实现类也不需要执行接口的<clinit>
⑤多线程下,虚拟机会保证<clinit>正确的加锁、同步。多个线程同时调用<clinit>,只有一条线程执行,其他阻塞直到<clinit>执行完。如果一个类的<clinit>耗时太长,会造成多个进程的阻塞

3、类加载器

3.1 类与类加载器

对于任意一个类,都需要由加载它的类加载器和这个类本身一起确定其在虚拟机中的唯一性。每一个类加载器都有独立的类命名空间。
比较两个类是否相同,不仅要两个类来源于同一个类,还需要使用同一个类加载器加载

3.2 双亲委派

三种类加载器:
①启动类加载器。由c++实现,是虚拟机的一部分。负责将存放在<JAVA_HOME>/lib目录中或被-Xbootclasspath参数指定的路径,且被虚拟机识别的类库加载到虚拟机中。
启动类加载器无法直接被java程序引用。
②扩展类加载器。由sun.misc.Launcher$ExtClassLoader实现,负责加载<JAVA_HOME>/lib/ext目录和java.ext.dirs指定的路径下的库
③应用程序类加载器。由sun.misc.Launcher$AppClassLoader实现,通过ClassLoader.getSystemClassLoader()获得,负责加载用户类路径所指定的类库。

双亲委派模型的工作过程:如果一个类加载器收到类加载的请求,它首先不会自己加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载器都是如此,直到顶层类加载器。如果父加载器反馈无法加载这个类(它的搜索范围中没有这个类),子加载器才会尝试加载。

好处:java类随着它的类加载器一起具备了一种带优先级的层次,保证了java程序的稳定运行。因为有自定义的Object时,最终只会加载系统的Object类,而不会加载自定义的Object类

3.3 破坏双亲委派模型

。。。

原创粉丝点击