美文网首页
JVM系列二(类加载器子系统)

JVM系列二(类加载器子系统)

作者: 叛逆与成功 | 来源:发表于2020-08-31 14:45 被阅读0次

    Java虚拟机(JVM)系列二

    类加载子系统

    一.类加载器子系统整体架构

    类加载器子系统.png
    • 类加载器子系统负责从文件或网络中加载Class文件(字节码文件),字节码文件在文件开头有特定文件标识
    • ClassLoader只负责Class文件的加载,至于能否运行,则由ExecutionEngine(执行引擎)负责
    • 加载的类信息存放在一个叫方法区的内存空间。方法区还会存放运行时常量池信息,可能还包括字符串变量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

    二.类加载器子系统具体加载过程分析

    1.加载(Loading)
    • 通过一个类的全限定名来获取定义此类的二进制流文件
    • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
    • 在内存中生成一个代表此类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
    2.链接(Linking)
    (1)验证(Verify)
    • 确保Class文件的字节流中信息符合当前虚拟机的要求,如文件开头特定标识(CAFEBYBE)
    • 主要包括四种验证:文件格式、元数据、字节码、符号引用验证
    (2)准备(Prepare)
    • 类变量分配内存并设置该类变量的初始值,即零值
    • 这里不包括用 final修饰的static,因为final在编译的时候就被分配了,准备阶段会显示初始化
    • 这里不会为实例变量分配初始化,类变量会分配到方法区中,实例变量会随对象一起分配到Java堆中。
    (3)解析(Resolve)
    • 常量池内的符号引用转换为直接引用的过程
    3.初始化(Initialization)
    • 初始化阶段就是执行类构造器方法<clinit>()的过程
    • 此方法不需定义,是javac编译器自动收集类中的所有类变量(静态变量)的赋值动作和静态代码块中语句合并而来
    • 构造器方法中的指令按照在源文件中的出现顺序执行
    • <clinit>() 不同于类的构造器
    • 若该类具有父类,JVM会保证在子类的<clinit>()执行前,父类的<clinit>()已经执行完毕
    • 虚拟机必须保证一个类的<clinit>()方法在多线程下被同步加锁(一个类只加载一次)

    三.类加载器分类

    类加载器分类.png
    • JVM支持两种类型的类加载器,即引导类加载器(BootstrapLoader)和自定义类加载器(User-Defined ClassLoader)
    • JVM规范定义,将所有派生于抽象类的ClassLoader的类加载器都划分为自定义类加载器,所以扩展类加载器系统类加载器也在自定义类加载器中包含。
    • Java核心类库都是引导类加载器进行加载的(Eg:String)
    1.引导类加载器(也叫启动类加载器 虚拟机自带的加载器)
    • c/c++ 语言开发的,嵌套在JVM中,在代码中获取不到,获取的时候会得到null
    • 它用来加载Java核心类库(JAVA_HOME/jre/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类
    • 不继承java.lang.ClassLoader,没有父加载器
    • 加载扩展类和系统类加载器,并制定为他们的父类加载器
    • 只加载包名为 java、javax、sun等开头的类
    2.扩展类加载器( 虚拟机自带的加载器)
    • Java语言编写,由sun.misc.Launcher$ExClassLoader实现
    • 派生于ClassLoader类
    • 父类加载器为启动类加载器
    • 从java.ext.dirs系统属性所指定目录中加载或者JDK安装目录 jre/lib/ext 子目录下加载类库
    3.系统类加载器(也叫应用程序类加载器 虚拟机自带的加载器)
    • Java语言编写,由sun.misc.Launcher$AppClassLoader实现
    • 派生于ClassLoader类
    • 父类加载器为启动类加载器
    • 负责加载环境变量classpath或系统属性java.class.path指定路径下的类库
    • 是程序中磨人的类加载器。一般来说,Java应用的类都由它加载
    4.自定义类加载器
    • 后续具体讲解
    5.ClassLoader
    • 它是一个抽象类,所有类加载器都继承自它(除了 引导类加载器)
    • 可通过以下方式获取ClassLoader


      获取加载器类型的方法.png

    四.双亲委派机制

    1.工作原来及演示
    • 当一个类加载器收到类加载请求,他并不会自己先加载,而是会把这个请求委托给他的父类加载器去执行
    • 如果父类加载器还存在其父类加载器,会继续向上委托,依次递归,请求将到达顶层的引导类加载器
    • 如果父类加载器可以完成加载任务,就成功返回,倘若父类加载器无法完成,子类加载器才会自己尝试加载。
    2.优势
    • 避免类的重复加载
    • 保护程序安全,防止核心API被篡改(沙箱安全机制)
         解释:自定义java.lang.String,添加main()方法,但是在加载自定义String类的时候,会率先使用引导类加载器加载,而引导类加载器在加载的时候会先加载jdk自带文件(rt.jar包中java.lang.String.class),报错信息说没有main()方法,就是因为加载的是tr.jar包中的String类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制

    五.其他

    1.JVM表示两个class对象是否为同一个类的必要条件
    • 类的完整类名必须一致,即包名
    • 加载此类的类加载器必须一样
    2.类的主动使用会进行类的初始化,类的被动使用不会
    3.JVM必须知道一个类是由引导类加载器加载的还是由用户类加载器加载的。如果是由用户类加载器加载的,则会将该类加载器的引用存储在方法区中。当解析一个类型到另一个类型的时候,必须确保两个类型的类加载器是一样的

    相关文章

      网友评论

          本文标题:JVM系列二(类加载器子系统)

          本文链接:https://www.haomeiwen.com/subject/sarnyhtx.html