深刻理解JVM-类加载

看完《深刻理解JVM》中关于类加载的一些我的总结,欢迎评论!java

 

类加载过程:数组

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们开始的顺序以下图所示:安全

加载->验证->准备->解析->初始化->使用->卸载数据结构

 

其中类加载过程:加载、验证、准备、解析、初始化多线程

加载、验证、准备、初始化发生的顺序是肯定的,而解析阶段不必定;线程

在某些状况能够在初始化阶段以后开始,以支持java的动态绑定对象

(由于类中的方法多是动态绑定)继承

 

java绑定:绑定是指把一个方法的调用与方法所在的类关联;分为如下两种方式:递归

静态绑定:在程序执行前方法已经被绑定,java当中的方法只有final,static,private和够早方法是前期半丁接口

动态绑定:运行时根据具体对象的类型进行绑定,java中全部的方法都是后期绑定;

 

 

加载:

加载阶段,虚拟机须要完成三件事:

1.经过一个类的全限定名来获取其定义的二进制字节流;

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

3.在java堆中生成一个表明这个类的java.lang.Class对象,做为方法区中这些数据的访问入口;

 

类加载器:

类加载器不止实现类的加载动做,

启动类加载器,扩展类加载器,应用程序类加载器,自定义加载器;

若是程序中没有自定义类加载器,默认的就是应用程序类加载器;

 

 

双亲委派模型:

每一次上面的类加载器叫作当前层类加载器的父加载器;使用组合的方式调用父加载器中的代码;

双亲委派工做流程:

若是一个类加载器收到了类加载的请求,它首先不会本身去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,所以,全部的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即没法完成该加载,子加载器才会尝试本身去加载该类。

 

好处:Java类随着它的类加载器一块儿具有了带有优先级的层次关系;一个类只会被一个加载器加载,保证java程序的稳定运行;

 

 

验证:

  验证的目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全;

  大体都会完成如下四个阶段的验证:

  文件格式的验证,元数据验证,字节码验证,符号引用验证;

 

 

准备:

  准备阶段是正式为类变量分配内存并设置类变量初始的阶段,这些内存都将在方法区中分配;

  需注意:

  1. 这时候进行内存分配的仅包括类变量(static),而不包括示例变量,实例变量会在对象实例化时随着对象一块分配在java堆中
  2. 这里所设置的初始值同城都是数据类型的默认值,而不是显示地赋予的值;
  3. 若是同时被static和final修饰,那么在准备阶段就会赋值

 

解析:

     解析阶段是虚拟机将常量池中的符号引用转化为直接引用的过程;

  1. 类或接口的解析:判断所要转化成的直接引用是对数组类型,仍是普通的对象类型的引用,从而进行不一样的解析;
  2. 字段解析:是对字段进行解析,会在本类中查找是否包含有简单名称和字段描述都与目标相匹配的字段,若是有则查找结束,没有则会按继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口;
  3. 类方法解析:对类方法的解析与字段步骤差很少,只是多了判断该方法所处的类仍是接口的步骤,并且对类方法的匹配搜索,先搜索父类,再搜索接口;
  4. 接口方法解析:递归向上搜索父接口就好了;

 

初始化:

     初始化是类加载最后一步,此阶段才真正开始执行类中定义的java代码。在准备阶段,类变量已经赋过一次系统初始值,初始化阶段则根据程序的主观计划去初始化类变量和其余资源;初始化是执行类构造器<clinit>方法的过程;

     clinit方法是由编译器自动收集类中全部类变量的赋值动做静态语句块中的语句合并产生的,静态语句块只能访问到定义在静态语句块以前的变量,对于定义在静态语句块以后的,只能赋值,不能访问;

     不须要显示地调用父类构造器,虚拟机保证子类的clinit执行以前父类的clinit已经执行完毕。

     若是类中没有静态语句块也没有对类的赋值操做,JVM能够不为这个类生成clinit方法;

     执行接口的clinit方法不须要先执行父接口的clinit,只有当父接口中定义的变量呗使用时,父接口才会被初始化;接口实现类初始化时也如此;

     虚拟机会保证clinit在多线程环境中被正确的加锁和同步;

相关文章
相关标签/搜索