类加载机制学习

简单讲下JVM中的类加载过程 JVM中的类加载和卸载的时机? 如何理解JVM中不一样类加载器的概念和做用? 简单讲下JVM中的双亲委派模型? 什么状况下会破坏双亲委派模型?为何?能否举个例子? Tomcat中的类加载机制有了解吗?为何这么设计? 实际开发中有遇到哪些类加载器相关的问题?你又是如何解决的? JVM之上的弱类型语言例如Groovy是如何实现?简单讲下动态类加载机制?java

类的加载和卸载算法

JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是class文件。日常咱们写的Java文件,须要编译为class文件才能交给JVM运行。能够这么说:C语言代码——>二进制文件——>计算机硬件,就至关于Java代码——>字节码文件——>JVM。JVM将指定的class文件读取到内存里,并运行该class文件里的Java程序的过程,就称之为类的加载;反之,将某个class文件的运行时数据从JVM中移除的过程,就称之为类的卸载。并发

class文件的运行时数据就是C++对象,也称为kclass对象,这些运行时数据在JDK7以前是放在永久代(PermGen),JDK8以后则放在元空间(Metaspace)。jvm

类的生命周期学习

Java类从被虚拟机加载开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段;其中验证、准备和解析又统称为链接(Linking)阶段。spa

类的加载的时机 虚拟机规范并未严格规定类加载的时机,跟具体的JVM虚拟机有关。类加载的最佳时机是解析Java字节码类文件中常量池符号的时候,Class.forName()、ClassLoader.loadClass()、反射API和JNI_FindClass均可以触发类加载,Hot JVM自身启动的时候也会触发类加载。设计

经过JVM参数中加 -verbose:class,能够在应用启动的时候打印类加载的过程,以下图所示:image 初始化这个阶段,JVM虚拟机给出了5种必须对类进行“初始化”的状况中间件

使用new关键字实例化对象的时候、读取或设置一个类的静态字段的时候、调用一个类的静态方法的时候;对象

使用java.lang.reflect包的方法对类进行反射调用的时候,若是类没有进行过初始化,则要先触发其初始化;blog

当初始化一个类的时候,若是发现其父类尚未被初始化,则要先初始化其父类;

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

在JDK1.7之后,动态语言支持的时候,若是一个java.lang.invoke.MethodHandle实例最后的结果是要执行第1种状况的操做,则也要进行初始化。 类的卸载时机 类的卸载跟采用的垃圾收集算法有关,在CMS中有两种方法卸载没必要要的类,一种是等到元空间(Metaspace)满了的时候触发FGC,另外一种是使用跟CMS并发收集算法相似的方式,不过对于元空间的阈值和触发CMS并发收集的阈值是独立的。更具体的能够参考以前的文章:CMS学习笔记。在这里,咱们只须要记住,JVM中一个类的卸载要知足下面这3个条件:

该类全部的实例对象都已被回收;

该类的类加载器对象已经被回收;

该类对应的java.lang.Class对象没有在任何地方被引用,没法在任何地方经过反射访问该类的方法。

类加载器的做用 类的加载是须要类加载器完成的,可是类加载器在JVM中的做用可不止这些。在JVM中,一个类的惟一性是须要这个类自己和类加载一块儿才能肯定的,每一个类加载器都有一个独立的命名空间。

不一样的类加载器,即便是同一个类字节码文件,最后再JVM里的类对象也不是同一个,下面的代码展现了这个结论:

能够看出,代码中使用自定义类加载器(myLoader)加载的jvm.ClassLoaderTest类和经过应用程序类加载器加载的类不是同一个类。综上,类加载器在JVM中的做用有:

  1. 将类的字节码文件从JVM外部加载到内存中

  2. 肯定一个类的惟一性

  3. 提供隔离特性,为中间件开发者提供便利,例如Tomcat