JVM学习 类加载子系统

JVM

哔哩哔哩 尚硅谷视频 宋红康老师

Java代码执行流程

JVM学习 类加载子系统

简图

JVM学习 类加载子系统

详细图

JVM学习 类加载子系统

1、类加载子系统

JVM学习 类加载子系统

类加载器子系统的作用

  • 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识
  • ClassLoader 只负责 class 文件的加载,至于它是否可以运行,则由Execution Engine决定
  • 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池的部分映射)

类的加载过程图

JVM学习 类加载子系统

1.1、加载阶段

加载

  • 通过一个类型的权限定名获取定义类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

1.2、链接阶段

验证(Verify)

  • 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全
  • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证

准备(Prepare)

  • 为类变量分配内存并且设置该类变量的默认初始值,即零值
  • 这里不包括用final修饰的static,因为final在编译的时候就分配了,准备阶段会显示初始化
  • 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中

解析(Resolve)

  • 将常量池内的符号引用转换为直接引用过程
  • 事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行
  • 符号引用就是一组符号来描述引用的目标,符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中,直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄
  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等,对应常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等。

1.3、初始化阶段

初始化

  • 初始化阶段就是执行类构造器方法()方法的过程
  • 此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来
  • 构造器方法中指令按语句在源文件中出现的顺序执行
  • ()不同于类的构造器。(关联:构造器是虚拟机视角下的())
  • 若该类具有父类,JVM会保证子类的()执行前,父类的()已经执行完毕
  • 虚拟机必须保证一个类的()方法在多线程下被同步加锁

安装 jclasslib is a bytecode viewer 来查看class字节码文件(Ider插件集成了的)

JVM学习 类加载子系统

JVM学习 类加载子系统

1.4、类加载器的分类

  1. JVM支持两种类型的类加载器,分别是引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)。
  2. 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器
    JVM学习 类加载子系统

测试:

public class ClassLoaderTest {
    public static void main(String[] args) {
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);

        //获取其上层,扩展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);

        //获取其上层:获取不到引导类加载器
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);

        //用户自定义类的加载器是谁
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);

        //String这个类是谁加载的:引导类加载器
        ClassLoader stringClassLoader = String.class.getClassLoader();
        System.out.println(stringClassLoader);
    }

    /*
     * 结果:
     * sun.misc.Launcher$AppClassLoader@18b4aac2
     * sun.misc.Launcher$ExtClassLoader@1b6d3586
     * null
     * sun.misc.Launcher$AppClassLoader@18b4aac2
     * null
     */
}

Java的核心类库都是引导类加载器加载的

虚拟机自带的加载器

  • 启动类加载器(引导类加载器:Bootstrap ClassLoader)
  • 这个类加载使用C/C++语言实现的,嵌套在JVM内部
  • 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类)
  • 并继承自java.lang.ClassLoader,没有父加载器
  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器
  • 出于安全的考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类
  • 扩展类加载器(Extension ClassLoader)
  • Java语言编写,由sun.misc.Launcher$ExtClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。
  • 应用程序类加载器(系统类加载器,AppClassLoader)
  • Java语言编写,由sun.misc.Launcher$AppClassLoader实现
  • 派生于ClassLoader类
  • 父类加载器为扩展类加载器
  • 它负责加载环境变量classpath或系统属性 java.class.path 指定路径下的类库
  • 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载的
  • 通过classLoader#getSystemClassLoader()方法可以获取该类加载器

测试:

package com.mhy.day01;

import sun.misc.Launcher;
import java.net.URL;

public class ClassLoaderTest01 {
    public static void main(String[] args) {
        //引导类加载器加载哪些路径下的文件
        System.out.println("引导类加载器加载的路径:");
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (URL urL : urLs) {
            System.out.println(urL);
        }
        //扩展类加载器加载哪些路径下的文件
        System.out.println("扩展类加载器加载的路径:");
        String property = System.getProperty("java.ext.dirs");
        for(String p : property.split(";")){
            System.out.println(p);
        }

        /*结果:
            引导类加载器加载的路径:
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/resources.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/rt.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/sunrsasign.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jsse.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jce.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/charsets.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/lib/jfr.jar
            file:/F:/Program%20Files/JavaIDEA/jdk/jre/classes
            扩展类加载器加载的路径:
            F:\Program Files\JavaIDEA\jdk\jre\lib\ext
            C:\WINDOWS\Sun\Java\lib\ext
         */
    }
}

1.5、双亲委派机制

工作原理

  1. 如果一个类加载器收到一个类加载的请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行
  2. 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,最终的请求回到达启动类加载器
  3. 如果父类加载器可以完成类加载任务,则成功返回;倘若父类加载器不能完成加载,子类加载器才会尝试去加载,这就是双亲委派机制

JVM学习 类加载子系统

测试:

这里在src文件下创建一个java.lang.String和自带的String同路径

package java.lang;

public class String {
    static {
        System.out.println("这是我们自己建立的String");
    }

    //如果在这个里面执行main方法
    /*
    错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
    public static void main(String[] args)
    否则 JavaFX 应用程序类必须扩展javafx.application.Application
     */
    public static void main(String[] args) {
        System.out.println("xxx");
    }
}

再在测试类中进行测试,看使用的String到底来自哪个String

package com.mhy.day01;

public class ClassLoaderTest02 {
    public static void main(String[] args) {
        String xx = new String();
        System.out.println("执行了该程序");
    }

    /*结果:
     * 执行了该程序
     */
}

1.6、类的主动使用和被动使用

  • 主动使用主要分为7种:
  • 创建类的实例
  • 访问某个类或接口的静态变量,或者对该静态变量赋值
  • 调用该类的静态方法
  • 反射(比如Class.forName(“路径”)))
  • 初始化一个类的子类
  • Java虚拟机启动时被表明为启动类的类
  • JDK7提供的动态语言的支持: java.lang.invoke,MethodHandle实例的解析结果 REF_getStatic、REF_putStatic、REF_invokeStatic句柄对应的类没有初始化,则初始化
  • 除了以上7种外,其他的Java对类的使用,就是被动使用

Original: https://www.cnblogs.com/shuisanya/p/16686379.html
Author: 水三丫
Title: JVM学习 类加载子系统

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581434/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 关于如何在Idea下进行多子项目及引用内部子项目情况下打包项目的方法

    近期在开发Java的时候遇到了如下的打包上的问题 需要将一个工程下面的子工程分别打包 有的子工程还包含了另一个子工程 在这种情况下打包会出现找不到子模块的情况。 JDK:1.8 开…

    Linux 2023年6月14日
    0100
  • Linux用户和用户组

    Linux用户和用户组 1.添加新的用户 (用户ID从500开始,0-99系统管理级别、100-499系统预留) useradd 选项 用户名 参数说明 选项: -c commen…

    Linux 2023年6月11日
    0102
  • 旅游清单一步搭建,Angular助力你的踏春计划

    春天的脚步愈发临近,相信很多小伙伴已经开始规划自己的踏春计划了,无论是欣赏名胜古迹,还是走访风土人文,你都需要提前准备一份旅游清单!有了这款Angular旅游计划应用,从地点到预算…

    Linux 2023年6月13日
    0116
  • Linux虚拟机追加扩展磁盘

    一、使用VMware给虚拟机追加磁盘 使用VMware打开虚拟机设置对话框,选择硬盘,点击右侧的扩展按钮,输入扩展后的磁盘容量。 点击扩展按钮。提示磁盘已成功扩展。 二、对闲置的空…

    Linux 2023年6月6日
    0126
  • typedef

    为类型定义别名 typedef int Int 这样 Int 就是 int类型的别名,就可以使用 Int来定一整形变量. 只需要在类型变量生命的基础上,再加一个关键字 typede…

    Linux 2023年6月13日
    094
  • Linux-shell

    shell 为注释 !执行脚本的 解释器 为bash 权限问题 remark 调试 bash -x man test 变量 —>默认必须全局变量 局部变量必须给local a…

    Linux 2023年6月7日
    086
  • 经典算法学习-计算汉明权重 SWAR(SIMD within a register)

    计算汉明权重算法 SWAR(SIMD within a register) 参考文章: [1] 简书:计算汉明权重的SWAR(SIMD within a Register)算法ht…

    Linux 2023年6月6日
    083
  • 014 Linux 线上高频使用以及面试高频问题——如何查找大文件并安全的清除?

    1 案例描述? 2 命令一(目录统计排序最佳命令) 3 命令二(最实用,目录和文件一起统计排序) (1)命令详情和说明 (2)du、head、sort、awk 详细说明参考已有文章…

    Linux 2023年5月27日
    0125
  • 继承、封装、多态的实现原理

    欢迎来到Java学习之继承、封装、多态的实现原理 目录 从JVM结构开始谈多态 JVM 的结构 Java 的方法调用方式 常量池(constant pool) 图 2. 常量池各表…

    Linux 2023年6月13日
    0114
  • haproxy-详解

    四层: LVS (Linux Virtual Server)HAProxy (High Availability Proxy)Nginx (1.9以上) 七层: HAProxyNg…

    Linux 2023年5月27日
    081
  • Python3.9.5安装

    基础环境:yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-de…

    Linux 2023年6月6日
    099
  • 存储过程,存储函数(Oracle)

    –打印hello world create or replace procedure sayhelloworld as –说明部分 begin dbms_output.put_…

    Linux 2023年6月14日
    087
  • Redis

    当你的才华不能撑起你的野心时,就是你该选择学习的时候了! Original: https://www.cnblogs.com/hofmann/p/16056013.htmlAuth…

    Linux 2023年5月28日
    092
  • c++的bind使用方法

    c++的bind使用方法 除了容器有适配器之外,其实函数也提供了适配器,适配器的特点就是将一个类型改装成为拥有子集功能的新的类型。其中函数的适配器典型的就是通过 std::bind…

    Linux 2023年6月14日
    097
  • 电脑中图标变白色教你怎么修复

    复制一下代码到文本文档中 另存为 .bat 然后点击好的配置文件右键以管理员身份运行 就会解决桌面变白的问题 @echo off taskkill /f /im explorer….

    Linux 2023年6月7日
    0102
  • linux学习记录

    查看所有系统服务 systemctl list-unit-files –type service -all 查看服务状态 sudo systemctl status servic…

    Linux 2023年6月7日
    084
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球