JVM-整体结构(2)

266 阅读2分钟

类加载子系统

03.JVM-类加载子系统.jpg

加载阶段

  1. 引导类加载器(BootstrapClassLoader
    • BootstrapClassLoader这个类是用c/c++编写的,嵌套在JVM内部
    • 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar or resources.jar or sun.boot.class.path) 路径下的内容
    • 不继承 java.java.lang.ClassLoader,没有父加载器
  2. 扩展类加载器(ExtClassLoader
    • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
    • 派生于ClassLoader
    • 父类加载器为启动类加载器
    • 从jdk的安装目录jre/lib/ext子目录下加载类库,如果用户创建的jar放在此目录下,也由ExtClassLoader加载
  3. 系统类加载器
    • Java语言编写,由sun.misc.Launcher$AppClassLoader
    • 派生于ClassLoader
    • 父类加载器为启动类加载器
    • 负责加载环境变量classpath或系统属性
    • 该类加载是程序中默认的类加载器
  4. 自定义类加载器
    • 这个主要交由开发者自行实现,继承ClassLoaderorURLClassLoader
    • 如果继承URLClassLoader可以避免自己实现findClass方法和获取字节码流

下面是获取类加载器具体代码

// 系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
// jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
System.out.println(systemClassLoader);

// 扩展类加载器
ClassLoader extClassLoader = systemClassLoader.getParent();
// jdk.internal.loader.ClassLoaders$PlatformClassLoader@682a0b20
System.out.println(extClassLoader);

// 试图获取引导类加载器,结果是无法获取到.
ClassLoader bootStrapClassLoader = extClassLoader.getParent();
// null
System.out.println(bootStrapClassLoader);

// 用户自定义类的加载器使用的是系统类加载器 systemClassLoader
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
// jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
System.out.println(classLoader);

// 获取引导类加载器可加载jar包的路径
for (URL url : Launcher.getBootstrapClassPath().getURLs()) {
    System.out.println(url.getPath());
}
// 获取扩展类加载器可加载的jar包的路径
String property = System.getProperty("java.ext.dirs");
for (String path : property.split(";")) {
    System.out.println(path);
}

双亲委派机制

  1. 如果一个类加载器收到类加载请求,会把这个请求委托给父类加载器执行
  2. 如果父类加载器还存在父类则向上委托,最终达到系统类加载器
  3. 如果父类可以自己完成加载则成功返回,否则交给子类加载器加载

04.JVM-双亲委派机制.jpg

链接阶段

验证(verify)

  1. 文件格式验证
  2. 元数据验证
  3. 字节码验证
  4. 符号引用验证码

准备(prepare)

  1. 为变量分配内存并设置初始值,即零值
  2. final修饰的常量再准备阶段会显示初始化

解析(resolve)

  1. 将常量池内的符号饮用转换为直接引用
  2. 解析动作主要包括:
    • 类、接口、字段、类方法、接口方法、方法类型等,对应常量池中的:CONSTANT_CLASS_INOFCONSTANT_FILEDREF_INOF等信息。

初始化阶段

以下过程全部按照声明变量的顺序进行赋值

  1. 父类静态变量和静态代码块赋值
  2. 自身的静态变量和静态代码块赋值
  3. 父类成员变量和构造函数赋值
  4. 自身变量构造函数赋值