java虚拟机-jvm类加载机制分享(2)

java虚拟机-jvm类加载机制分享(2)

大家好!在上一期分享了虚拟机内存分配情况,以及各区域都存放那些数据。这期我们分享一下类加载机制!

类从被加载到虚拟机内存中开始,到卸载出内存为止,生命周期如下图:

java虚拟机-jvm类加载机制分享(2)

什么情况下需要开始进行类加载过程的第一个阶段:加载? java虚拟机并没有进行强制约束,但是对于初始化阶段虚拟机规范严格规定有且只有一下5种情况必须立即对类进行“初始化”:

1、遇到newgetstaticputstaticinvokestatic这4个字节码指令时。

2、使用java.lang.reflect包的方法对类进行反射调用时。

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

4、当虚拟机执行一个main方法时,会首先初始化这个主类。

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

在完成初始化之前,还有好几个步骤,下面我们看一下每一步都有哪些操作:

类加载过程分为:加载、验证、准备、解析、初始化

示意图如下

java虚拟机-jvm类加载机制分享(2)

上图是小编自己绘制的一个流程,其中内容或者步骤有不对的地方,还望广大网友在评论区批评指正!

具体步骤如下:

1.加载 : 分以下3步

a.通过一个类的全限定名来获取定义此类的二进制字节流

这个步骤在java虚拟机外部实现,实现这个动作的代码模块称为“类加载器

从开发人员的角度来讲,有3中系统提供的类加载器

1) 启动类加载器

2) 扩展类加载器

3) 应用程序类加载器(系统类加载器)

类加载之间的这种层次关系称为类加载器的双亲委派模型(顶层是启动类加载器)

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

c.生成这个类的 java.lang.Class 对象,作为方法区这个类的数据访问入口

2.验证: 主要是验证 Class 文件的字节流包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身安全

包括:a.文件格式验证 b.元数据验证 c.字节码验证 d.符号引用验证

3.准备: 正式为类变量分配内存并设置类变量的初始值,这些变量所使用的内存都在方法区中进行分配

“通常情况”下初始值是零值

4.解析: 是虚拟机将常量池内的符号引用替换为直接引用的过程(虚拟机没有规定此阶段发生的具体时间)

5.初始化: 类加载的最后一步,开始执行类中定义的java程序代码,此阶段是执行类构造器() 方法的过程

会出现“非法向前引用”:静态语句块中只能访问到定义在它之前的变量,在它之后的变量,在静态语句块中可以赋值但不能访问,具体内容如下图:

java虚拟机-jvm类加载机制分享(2)

类加载过程中还有一部分在加载过程中,会使用到类加载器,下面说说类加载器!

类加载器

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在java虚拟机中的唯一性,每个类加载器都拥有一个独立的类名称空间。若被同一个虚拟机加载,只要它们的类加载器不同,那这两个类就必定不相等。


双亲委派模型工作过程:如果一个类加载器收到了类加载请求,它首先不会自己加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,所有的加载请求都是会传送到顶层的启动类加载器,只有当父类加载器反馈自己无法加载时,子加载器才会尝试去加载。双亲委派模型要求除了顶层的启动类加载器外,其余的加载器都应当有自己的父加载器,这里的类加载器之间不会以继承的关系来实现,而是都使用组合关系来复用父加载器的代码。

java虚拟机-jvm类加载机制分享(2)

启动类加载器:(Bootstrap ClassLoader)它负责加载存放在lib目录下的,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库加载到虚拟机内存中。启动类加载器是无法被Java程序直接引用的。

扩展类加载器:(Extension ClassLoader) 该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

应用程序类加载器:(Application ClassLoader) 也称为系统类加载器,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

双亲委派模型对于保证java程序的稳定性很重要,实现逻辑很清晰:先检查是否已经被加载过,若没有加载则调用父加载器的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器,若父类加载器失败,抛出 ClassNotFoundException 异常后,再调用自己的findClass() 方法进行加载。

本期类加载机制就是这些,请大家打赏点赞,多多评论!下期我们分享jvm的垃圾回收算法和垃圾回收机制。


分享到:


相關文章: