JVM浅析总结(类加载器)
# JVM类加载器(类装载子系统)
# 类的加载过程
类加载过程步骤:加载>链接(包含验证,准备,解析)>初始化>使用>卸载
- 加载(loading):通过类的全限定名(全限定名 = 包名+类型,eg:java.lang.String)获取此类的字节流(此字节流可以是通过读取.class文件,也可以通过网络io流,或者其他压缩包等途径获取),将流代表的静态存储结构(.class文件)转化为方法区(作为一个内存区域,类模板对象,jdk1.8以前永久代,1.8之后元空间)的运行时数据结构,在堆内存中生成一个代表该类的java.lang.class对象,作为方法区这个类的各种数据的访问入口
- 链接(linking)(包含验证(verification),准备(preparation),解析(resolution))
项目 | 具体流程 |
---|---|
验证(verification) | 确保class文件的字节流符合虚拟机规范,确保安全以及正确,主要的验证方式:文件格式验证(魔数,版本,长度检查等),元数据验证,字节码验证符号引用验证; |
准备(preparation) | 为类的静态变量分配内存并且设置该类的默认初始值(零值), 可参考:Java 基本数据类型 (opens new window);注意final修饰的变量即常量在编译时刻就已经分配值了(在常量池)(eg:public final int value=123),准备阶段显示赋值; |
解析(resolution) | 将常量池(jdk1.8元空间中)内的符号引用转换为直接引用(内存地址),符号引用是一组用来描述所引用的目标,符号引用字面量形式定义在java虚拟机规范的class文件格式中;通俗的讲就是通过常量池的符号直接定位到代表该符号的真实文件的存储路径 |
- 初始化(Initialization)初始化就是执行类构造器方法<clinit(class init)>的过程,此方法是javac编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并而成,构造器方法中指令按语句的源文件中出现的顺序执行(idea 插件jclasslib查看字节码),clinit方法是类变量方法变量赋值才会产生,而类的构造器则在虚拟机下面会产生init方法(只有类具有静态变量或者静态代码块才会在字节码中生成clinit方法),如果编译类具有父类,jvm会先保证父类的clinit方法执行完毕,再执行子类的clinit,虚拟机必须保证一个类clinit方法在多线程下被同步加锁 ,并且初始化是否需要执行也取决于类是否主动使用,主动使用就执行初始化过程,被动使用则不执行,可参考:类的主动使用被动使用 (opens new window)
- 使用(Using) 开发过程中各种编码做的操作,new 一个实例,实例.方法等操作
- 卸载(Unloading) 在平常的日常开发过程中很难做到卸载,可参考:Java类的卸载机制 (opens new window)
# 类加载器
类加载器运用于类加载过程中的加载(loading)阶段
jvm支持的两种类加载器:
- 引导累加载器(Bootstrap ClassLoader)
- 自定义类加载器(User-Defined ClassLoader),jvm定义的自定义类加载器是所有派生与抽象类ClassLoader的类加载器都统称为自定义类加载器
我们常见的类加载器有三个:
加载器 | 说明 |
---|---|
Bootstrap Class Loader | 引导累加载器,C/C++语言实现,无法通过程序获取到,加载java的核心类库(JAVA_HOME/jre/lib/rt.jar,resources.jar或sun.boot.class.path路径下的内容,只加载java,javax,sun开头的类) |
Extension Class Loader | 拓展类加载器,java语言编写,由sun.misc.Launcher$ExtClassLoader实现,从jdk的安装目录jre/lib/ext子目录下加载类库 |
System Class Loader(AppClassLoader) | 系统类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载环境变量java.class.path指定的类库,用户自定义的类默认使用系统类加载器加载(程序编写类的默认加载器) |
用户自定义类加载器 | 定制加载方式,自定义存在的意义:隔离加载类,修改类加载方式,拓展加载源,防止源码泄露,自定义类加载器的简单实现在jdk1.2之前通过继承抽象类java.lang.ClassLoader是一个抽象类,除引导类加载器都直接或间接继承并重写loadClass方法,jdk1.2之后不再建议覆盖loadClass方法,建议把自定义的类加载逻辑写在findClass方法中,如无较为复杂的逻辑可直接集成URLClassLoader类 |
类加载的双亲委派机制:如果一个类加载器收到类加载请求,不会直接加载,而是委托给父类加载器加载,一直递归往父类委托,直到顶层的引导类加载器,递归加载到该类则直接返回,如果递归过程中一直未加载到该类,子加载器才会自己加载
双亲委派机制
优缺点 | 说明 |
---|---|
弊端 | 加载过程单向,顶层加载器无法候去底层加载器加载的 |
优势 | 避免类的重复加载;保护程序安全,避免核心类库被篡改(沙箱安全机制) |
上次更新: 2023/12/18, 13:54:07