Java Virtual Machine ClassLoader
下面讨论的都是在JDK8 platform。
JVM内存区中要创建对象,就必须需要把.class文件加载到内存中才能使用。
类加载大概分为5个阶段
加载
、验证
、准备
、解析
、初始化
加载 Loading
加载的过程,就是JVM读取.class 文件的二进制字节流,将这个字节流代表的静态存储 结构 转化为方法区的运行时数据结构,然后在Heap中创建一个对象,作为方法区这个类的访问入口。除了从.class文件获取,也可以从jar。war中获取,还可以通过动态代理proxy生成
验证 Verification
验证主要是用于确保class文件符合JVM的要求
准备 Prepatation
准备阶段是在方法区中为类变量(static 变量)分配内存并设置初始值。此时的分配变量属于类变量,不包括实例变量。 static变量在准备阶段初始为0,如果设置其他自定义值就需要在对象初始化的时候完成。但是如果是final类型,
public static final int value =1111;
JVM在准备阶段就会给该变量赋值1111。
解析 Resolution
主要是对类或接口,字段,类方法,接口方法,方法类型,方法句柄,调用点等7类符号引用进行处理。分别是常量池的
CONSTANT_Class_info
,
CONSTANT_Fieldref_info
,CONSTANT_Methodref_info
,CONSTANT_InterfaceMethodref_info
,CONSTANT_MethodType_info
,CONSTANT_MethodHandle_info
,CONSTANT_Dynamic_info
,CONSTANT_InvokeDynamic_info
初始化 Initialization
通过执行<clinit>
方法为类进行初始化。<clint>
方法是有编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}中的语句合并产生的。
JVM保证子类的<clint>
方法执行前,父类的<clint>
方法已经执行完毕,所以意味着父类中定义的静态语句块要优先与子类的变量赋值操作
类加载器 ClassLoader
先上图 3大类加载器,启动类加载器,扩展类加载器,应用程序类加载器。
Coder还可以extend ClassLoader来自定义加载器。
启动类加载器 BootStrap ClassLoader
负责加载核心的类库\lib
目录下的或者被-Xbootclasspath
参数指定的路径而且是JVM能识别的。BootStrap ClassLoader
不能被java程序直接使用,当编写自定义类加载器是,需要把加载请求委派给引导类加载器处理。
扩展类加载器 Extension ClassLoader
负责加载\lib\ext
,或者是被java.ext.dirs
系统变量所指定的路径下所有的库。
应用程序类加载器 Application ClassLoader
负责加载用户路径classpath
上的类库
双亲委派模型 Parents Delegation Model
双亲委派模型要求除了Bootstrap ClassLoader
之外,其他的类加载器都应该有自己的父类加载器。这里加载器之间的父子关系不是继承来实现的,而是通过组合Composition
来复用父加载器。
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类, 而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此, 因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类) 时, 子加载器才会尝试自己去完成加载 。
这个特别的机制是为了保障类的唯一性和安全性。确保各自的类只会被对应的加载器加载
。
jvm = Java Virtual Machine
参考:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html
Tag
jvm
classloader