您的位置:首页 > 编程语言 > Java开发

Jvm类加载机制理解

2017-03-14 17:29 239 查看
虚拟机把描述类的数据从class文件加载到内存,并对数据进行验证,准备,解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

一、类加载主要分为以下几个阶段:

加载

验证

准备

解析

初始化

使用

卸载

关于初始化:

(1) 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

(2) 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

(3) 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

(4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

(5)当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic等方法句柄,并且这个方法的句柄所对应的类没有进行初始化,则需要先触发初始化。

只有上述五种情况会触发初始化,也称为对一个类进行主动引用,除此以外,所有其他方式都不会触发初始化,称为被动引用。

加载

此阶段虚拟机主要完成以下事情:

通过一个类的全限定名获取此类的二进制流。

将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据访问入口。

验证

主要是为了确保Class文件中的字节流中的包含的信息符合JVM的要求。主要包含下面4个阶段的检验动作:文件格式验证元数据验证字节码验证符号引用验证

准备

这个阶段正式开始为类变量分配内存并设置类变量初始值。这些变量所使用的内存都将在方法区中分配,这是对于static变量赋值为0所说的

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。包括了类或接口的解析,字段的解析,接口方法的解析。

初始化

初始化阶段是执行类构造器 clinit 的过程。真正开始执行类中定义的java程序代码。

二、类加载器

1、什么是类加载器??

“通过一个类的全限定名来获取描述此类的二进制字节流“这个动作被放到jvm外部去实现了,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码就是类加载器

tips:比较两个类是否相等,也就是isInstance()方法,equals()方法返回值是否相等。对于任何一个类,都需要它的加载器这个类本身一同确立其在java虚拟机中的唯一性。每一个类加载器,都有一个独立的类名称空间

2、类加载器分类

类加载器分为启动类加载器,是虚拟机自身的一部分由C++实现。另一种是所有其他的类加载器,这些类加载器是由java语言实现的,独立于虚拟机外部,且全部继承于抽象类java.lang.ClassLoader

另一种分类方法是:

启动类加载器负责加载JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器无法被Java程序直接引用。

扩展类加载器负责加载JAVA_HOME\lib\ext目录中的所有类库,开发者可以直接使用扩展类加载器。

应用程序类加载器:该类加载器也称为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

双亲委派模型:



要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。

实现过程:

如果一个类加载器收到了类加载的请求,他首先会把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该到了顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jvm java