类加载过程
加载阶段
在硬盘上查找并通过IO读取字节码文件(类使用时才加载)
连接阶段
执行校验、准备、解析步骤
校验阶段
校验字节码文件的正确性(重要但不必须,可通过-Xverifynone关闭)
- 校验文件格式是否是class文件格式
- 校验元数据是否符合Java规范
- 校验字节码语义是否合法
- 校验符号引用
准备阶段
- 为静态变量分配内存空间
- 赋予静态变量默认值
赋默认值不是赋编码时程序员指定的值,数值型数据默认值一般为0,引用型数据默认值一般为null。动态变量是在堆的对象中的实例数据区进行存储,在实例化对象时分配空间。
解析阶段
将符号引用转化为直接引用,该阶段会把一些静态方法(符号引用 如main())替换为指向数据所在内存的指针或句柄等(直接引用),这就是静态链接。
- 静态链接是类加载时完成
- 动态链接是类运行时完成,如栈帧中的动态链接
符号引用在字节码文件中已经定义好了,符合Java规范,与虚拟机内部内存布局无关,在不同的虚拟机中都可正常运行。而直接引用与内存布局是有关的,不同虚拟机对同样符号引用翻译出来的直接引用格式可能不同。
javap -v xxx.class 指令执行后的常量池(Constant Pool)内存储了大量的符号引用。
初始化阶段
为静态变量赋程序员指定的值,执行静态代码块。
使用阶段
卸载阶段
类加载器
核心类和扩展类在JVM启动时一次性全部加载
启动类加载器
负责加载支撑JVM运行的位于JDK/JRE/lib目录下的核心类库,比如rt.jar,charsets.jar等
扩展类加载器
负责加载支撑JVM运行的位于JDK/JRE/ext扩展目录下的类库
应用程序类加载器
负责加载ClassPath路径下的类库,主要就是加载自己写的类
自定义加载器
负责加载自定义路径下的包
public class EurekaApplication {
public static void main(String[] args){
//SpringApplication.run(EurekaApplication.class,args);
System.out.println(String.class.getClassLoader());//这句和其他两句不一样,是因为启动类加载器是c语言编写的,访问不到ClassLoader,返回为null,无法像另外两个getClass
System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
System.out.println(EurekaApplication.class.getClassLoader().getClass().getName());
}
}
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader