在面试中通常会问到关于Java虚拟机的内容,重点在类机载机制、运行时数据区、GC垃圾回收,JVM性能调优
等,
运行时数据区相关整理请阅读Java虚拟机之内存结构
GC垃圾回收相关整理请阅读GC垃圾回收
本文主要是对类加载器相关知识点进行整理;
类加载器机制
类加载器机制是指:代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型 。
-
类的加载
1、通过一个类的
全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)
。而获取的方式,可以通过jar包、war包、网络中获取、JSP文件生成等方式。2、将这个字节流所代表的
静态存储结构转化为方法区的运行时数据结构
。这里只是转化了数据结构,并未合并数据。3、在
内存中生成一个代表这个类的java.lang.Class对象
,作为方法区
这个类的各种数据的访问入口
。 -
类的连接
类的加载过程后生成了类的java.lang.Class对象,接着会进入连接阶段,
连接阶段负责将类的二进制数据合并入JRE(Java运行时环境)中
。类的连接大致分三个阶段。1、验证:验证被加载后的类是否有正确的结构,类数据是否会符合虚拟机的要求,确保不会危害虚拟机安全。
2、准备:为类的静态变量(static filed)在方法区分配内存,并赋默认初值(0值或null值)。如
static int a = 100;静态变量a就会在准备阶段被赋默认值0
。对于一般的
成员变量是在类实例化时候,随对象一起分配在堆内存中
。另外,
静态常量会在准备阶段赋程序设定的初值
,如static final int a = 666; 静态常量a就会在准备阶段被直接赋值为666,对于静态变量,这个操作是在初始化阶段进行的。3、解析:将常量池内的符号引用换为直接引用。
-
类的初始化
真正开始执行定义的java代码; 初始化阶段是执行类构造器()方法的过程 ;当初始化一个类的时候,如果发现其父类没有进行过初始化,则首先触发父类初始化 。
都有哪些类加载器
- 启动类加载器:负责加载%JAVA_HOME%\bin目录下的所有jar包,或者是-Xbootclasspath参数指定的路径
- 扩展类加载器: 负责加载%JAVA_HOME%\bin\ext目录下的所有jar包,或者是java.ext.dirs参数指定的路径
- 应用程序类加载器:负责加载用户类路径上所指定的类库,开发者可直接使用这个类加载器;
除了顶层的启动类加载器外,其他的类加载器都应该有自己的父类加载器,以组合关系复用父类加载器的父子关系,注意,这里的父子关系并不是以继承关系实现的
双亲委派模型
如果一个类加载器收到了类加载的请求,先把这个请求委派给父类加载器去完成(所以所有的类加载请求最终都会传递到顶层的启动类加载器中),只有当父类加载器反馈自己无法完成该类加载请求,子加载器才会尝试自己去加载。
自定义了一个java.lang.Object会被加载吗?不会,无论哪一个类加载器要加载这个类,最终都会委派给处于模型顶端的启动类加载器进行加载,而启动加载器会加载rt.jar下的Object,从而不会执行自定义的,这种机制保证了各种类加载器环境变量中都是同一个类,若没有双亲委派机制,那么各个类加载器都自行执行的话,那么系统中将会出现多个Object类,从而出现一片混乱。