JVM之类加载

JVM之类加载

类的加载指的是将编译好的class类文件中的字节码读入到内存中,将其放在方法区内并创建对应的Class对象。

Screen Shot 2020-09-05 at 10.53.57 AM
  1. class文件存在本地硬盘上,在执行时加载到JVM中,根据这个文件可以实例化出n个一模一样的实例。
  2. class文件加载到JVM中,被称为DNA元数据模板,放在方法区中。
  3. 在.class文件 -> JVM -> 最终成为元数据模板的过程中,ClassLoader就扮演一个快递员的角色。

加载、链接、初始化

加载是文件到内存的过程。

链接又包括验证、准备、解析三步

  • 验证是对类文件内容验证
  • 准备阶段是进行内存分配
  • 解析主要是解析字段、接口、方法

初始化:主要完成静态块执行与静态变量的赋值

初始化的触发条件包括创建类的实例的时候、访问类的静态方法或者静态变量的时候、Class.forName()反射类的时候、或者某个子类被初始化的时候。


类加载器

bootstrap启动类加载器、扩展类加载器和应用加载器也叫系统加载器。

启动类加载器加载java home中lib目录下的类,扩展加载器负责加载ext目录下的类,应用加载器加载classpath指定目录下的类。

java的类加载使用双亲委派模式,即一个类加载器在加载类时,先把这个请求委托给自己的父类加载器去执行,如果父类加载器还存在父类加载器,就继续向上委托,直到顶层的启动类加载器。

img

系统类加载器(System Class Loader) < 扩展类加载器(Extension Class Loader) < 引导类加载器(Bootstrap Class Loader)

引导类加载器(Bootstrap ClassLoader)

  1. 用来加载Java的核心库,(JAVA_HOME/jre/lib/rt.jar、resources.jar、或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类。
  2. 并不继承自java.lang.ClassLoader ,没有父加载器。
  3. 加载扩展类和应用程序类加载器,并指定为他们的父类加载器。
  4. 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。

扩展类加载器(Extension ClassLoader)

从java.ext.dirs系统属性所指定的目标中加载类库,或从JDK的安装目录jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的Jar放在此目录下,也会自动由扩展类加载器加载。

系统类加载器(System ClassLoader)

它负责加载环境变量classpath或系统属性 java.class.path指定下的类库。

用户自定义类加载器

用户根据自定义需求,自由的定制加载的逻辑,继承AppClassLoader,仅仅覆盖findClass()即将继续遵守双亲委派模型。


NoClassDefFoundError VS ClassNotFoundException

ClassNotFoundException is a checked exception

类加载器尝试加载类时候,如果找不到指定的类,就会报 ClassNotFoundException 异常

  • Class.forName(“完整类名”)
  • ClassLoader.loadClass(“完整类名”)
  • ClassLoader.findSystemClass(“完整类名”)

NoClassDefFoundError 是error,jvm会退出

当jvm在编译的时候这个类是存在的,但是运行的时候找不到这个类了,就会报 NoClassDefFoundError 错误。

NoClassDefFoundError occurs when class was present during compile time and program was compiled and linked successfully but class was not present during runtime

e.g. when class A is using class B and class B is not on classpath, NoClassDefFoundError will be thrown.


https://zhuanlan.zhihu.com/p/54693308