虚拟机类加载
类加载的时机
类从被加载到虚拟机内存开始,到被卸载出内存为止,生命周期包括:
①加载 -> |②验证 -> ③准备 -> ④解析| -> ⑤初始化 -> ⑥使用 -> ⑦卸载 |← 连接阶段link →|
虚拟机规范没有强制约束类加载的时机;
严格规定了有且只有五种情况必须立即对类进行 (有且只有)
⑤初始化:
1.遇到 new,getstatic,putstatic,invokestatic这4条字节码指令,如果类没初始化,则触发初始化,场景:new关键字实例化,读取或者设置一个类的静态字段,一起调用一个类的静态方法的时候
2.使用java.lang.reflect对类进行反射调用的时候,如果类没初始化,则需要先触发
3.当初始化一个类,如果父类没初始化,则先触发器父类初始化
4.当虚拟机启动,用户需要指定要一个要执行的主类,虚拟机会初始化这个类
5.如果一个java.lang.invork.methodHandle实例最后的解析结果REF_getStatic,REF_getStatic,REF_getStatic的方法句柄,并且这个句柄所对应的类没进行过初始化,则需要触发其初始化
1.加载
`加载`是`类加载`过程的一个阶段
加载阶段,虚拟机完成以下三件事:
1.通过一个类的全限定名来获取此类的二进制字节流
补充:
-从ZIP包中读取,成为日后WAR,JAR包格式的基础
-从网络中读取,典型的Applet
-运行时计算生成,这种场景使用最多的就是动态代理技术,java.lang.reflect.Proxy中
-由其他文件生成,典型的JSP
-从数据库中读取,少见的很
2.将这个字节流所代表静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据的访问入口.
2.验证
这是虚拟机安全保证中非常重要的一步:
验证是连接阶段的第一步,这一阶段的目的为为了确保Class文件的字节流包含的信息符合当前虚拟机的要求,并不会危害虚拟机的安全
1.文件格式验证
2.元数据验证字节码验证
3.字节码验证
4.符号引用验证
3.准备
准备阶段是正式为类变量分配内存,并设置初始值的阶段(仅包括static修饰的变量),
其次这里所说的初始值,"通常情况"下,是数据类型的零值
`public static int value = 123`
这里准备阶段过后的初始值是 0, 而不是123,
因为这个时候尚未开始执行任何java方法
4.解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,
类加载器
类加载阶段中通过一个类的全限定名来获取描述此类的二进制字节流,这个动作放到Java虚拟机外部去实现,以便 让引用程序自己决定如何去获取所需要的类,实现这个动作的代码模块称类加载器 ```text 对于任意一个类,都需要由加载它的类和这个类本身一同确立其在java虚拟机中的唯一性. 一个类文件被不同的类加载器加载,是两个独立的类
### 双亲委派
```text
从Java虚拟机的角度,只存在两种不同的类加载器:
1.启动类加载器(C++实现,属于jvm自身部分)
2.其他的类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader
更精细的划分
启动类加载器:BootStrap ClassLoader
负责加载%JAVA_HOME%/lib,如rt.jar目录中的类,并且是虚拟机识别的
扩展类加载器:Extension ClassLoader[sum.misc.Launcher$ExtClassLoader]
负责加载%JAVA_HOME%/lib/ext这个目录中的类,可以被开发者直接使用
应用类加载器:Extension ClassLoader[sum.misc.Launcher$AppClassLoader]
这个类加载器是ClassLoader中getSystemClassLoader()方法的返回值,
所以一般称为系统类加载器,负责加载用户类路径上所指定的类库.
一般情况下,是这个应用默认的类加载器