【Jvm】Jvm类加载机制

类加载时机

虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是虚拟机的类加载机制。

在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的

类加载的过程

类的生命周期
在这里插入图片描述
PS:
NoClassDeFoundError:发生在类生命周期中解析阶段找不到相应的类
ClassNotFoundException发生在类生命周期的加载阶段,找不到相应的类。

为支持运行时绑定,解析过程在某些情况下可在初始化之后再开始,除解析过程外的其他加载过程必须按照如图顺序开始。

加载

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

验证

验证是连接阶段的第一步,这一阶段的目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  1. 文件格式验证:如是否以魔数 0xCAFEBABE 开头、主、次版本号是否在当前虚拟机处理范围之内、常量合理性验证等。
    此阶段保证输入的字节流能正确地解析并存储于方法区之内,格式上符合描述一个 Java类型信息的要求。
  2. 元数据验证:是否存在父类,父类的继承链是否正确,抽象类是否实现了其父类或接口之中要求实现的所有方法,字段、方法是否与父类产生矛盾等。
    第二阶段,保证不存在不符合 Java 语言规范的元数据信息。
  3. 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。例如保证跳转指令不会跳转到方法体以外的字节码指令上。
  4. 符号引用验证:在解析阶段中发生,保证可以将符号引用转化为直接引用。

可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

准备

类变量分配内存并设置类变量初始值,这些变量所使用的内存都将在方法区中进行分配。

public static int value = 123
在准备阶段过后的初始值是0 而不是123,因为这个时候没有正在的执行过java代码;而把value赋值为123的putstatic指令是程序被编译后,存放在类构造器clinit()方法中,将会在初始化的时候执行

特殊情况:final修饰
public final static int value = 123
被final修饰之后就是常量属性,在准备阶段虚拟机就会直接赋值,不需要等到初始化阶段;

解析

虚拟机将常量池内的符号引用替换为直接引用的过程。
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符 7 类符号引用进行。
为支持运行时绑定,解析过程在某些情况下可在初始化之后再开始,除解析过程外的其他加载过程必须按照如图顺序开始

NoClassDeFoundError:发生在类生命周期中解析阶段找不到相应的类

初始化

到初始化阶段,才真正开始执行类中定义的 Java 程序代码,此阶段是执行 clinit() 方法的过程。
clinit() 方法是由编译器按语句在源文件中出现的顺序依次自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生的。(不包括构造器中的语句。构造器是初始化对象的,类加载完成后,创建对象时候将调用的 init() 方法来初始化对象)

静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问
如下:
在这里插入图片描述
这样的写法是正常的; 但是如果把声明换个位置
在这里插入图片描述
这样就会提示 非法前向引用 ; 进而说明 clinit() 方法是由编译器按语句在源文件中出现的顺序 依次自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生的
总结一下:

  1. 初始化接单是执行 clinit() 方法的过程
  2. clinit() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并产生的
  3. clinit() 不需要显式调用父类,的初始化方法 clinit(),虚拟机会保证在子类的 clinit() 方法执行之前,父类的 clinit() 方法已经执行完毕,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作。
  4. clinit() 方法对于类或接口来说并不是必需的,如果一个类中没有静态语句块,也没有对变量的赋值操作,那么编译器可以不为这个类生成 clinit() 方法
  5. 虚拟机会保证一个类的 clinit() 方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 clinit() 方法,其他线程都需要阻塞等待,直到活动线程执行 clinit() 方法完毕。

对于初始化阶段,虚拟机规范规定了有且只有 5 种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始)

  1. 遇到new、getstatic 和 putstatic 或 invokestatic 这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。对应场景是:使用 new 实例化对象、读取或设置一个类的静态字段(被 final 修饰、已在编译期把结果放入常量池的静态字段除外)、以及调用一个类的静态方法。
  2. 对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  3. 当初始化类的父类还没有进行过初始化,则需要先触发其父类的初始化。(而一个接口在初始化时,并不要求其父接口全部都完成了初始化)
  4. 虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),
    虚拟机会先初始化这个主类。
  5. 当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

类加载器

即使两个类来源于同一个 Class 文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类也不相等。

双亲委派模型

双亲委派模型的加载类逻辑可参考如下代码:
在这里插入图片描述

    // 代码摘自《深入理解Java虚拟机》
    protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // 首先,检查请求的类是否已经被加载过了
        Class c = findLoadedClass(name);
        if (c == null) {
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
            // 如果父类加载器抛出ClassNotFoundException
            // 说明父类加载器无法完成加载请求
            }
            if (c == null) {
                // 在父类加载器无法加载的时候
                // 再调用本身的findClass方法来进行类加载
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

自定义类加载器

  1. 继承 java.lang.ClassLoader
  2. 重写父类的 findClass() 方法,JDK 的 loadCalss() 方法在所有父类加载器无法加载的时候,会调用本身的 findClass() 方法来进行类加载,因此我们只需重写 findClass() 方法找到类的二进制数据即可。

参考文章

  1. 深入理解虚拟机
已标记关键词 清除标记
相关推荐
<p style="color: #676767; font-size: 14px; background-color: #ffffff;"><strong><span style="color: #008781; font-size: 16px;">为什么要学JVM</span></strong></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JVM是JAVA的老祖宗,一切JAVA代码都运行在JVM之上,只有深入理解和掌握虚拟机才能写出更强大的代码。</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JVM是高级程序员的必备技能,是程序员进阶,拿高薪的必备技能。</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JVM是各大互联网公司笔试、面试的重中之重,据统计头部的10家互利网公司,均将JVM作为笔试面试内容。</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JVM内容庞大、并且复杂难学,通过视频学习是最佳的掌握手段。</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JVM的字节码、垃圾回收、性能调优、故障排除、在线诊断都是高级程序员的必备技能。</span></p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;"><strong><span style="color: #008781; font-size: 16px;">课程介绍</span></strong></p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">本课程总计102课时,从什么是JDK讲起,绝对的0基础入门。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">课程总计分为理论篇和实战篇两个大部分,绝对是全网最详细的JAVA虚拟机视频教程。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">课程涵盖JVM基础、字节码逐项解析、加载器、内存结构、回收算法、垃圾收集器等理论章节。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">也包含GC日志详解、垃圾手机、性能调优、故障排除、线程死锁、内存溢出、CPU飙升、快照分析全部囊括。实战章节。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">特别包含阿里巴巴在线诊断神器Arthas教程。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">jcmd、jinfo、jstap、jmap、jconsole、jvisualvm、jstat、jmx、jprofile、jps全部工具的使用一网大金</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;"><strong><span style="color: #008781; font-size: 16px;">课程资料</span></strong></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">课程附带配套2个项目源码</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">159页高清PDF理论篇课件一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">89页高清PDF实战篇课件一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">Unsafe源码PDF课件一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">字节码可视化解析工具</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">GC日志可视化分析工具</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">命令行工具cmder</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">class_stats字段说明PDF文件</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">jcmd Thread.print解析说明文件</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; background-color: #ffffff;"><span style="font-size: 14px;">JProfiler内存分析工具说明文件</span><span style="font-size: 14px;">一份</span></p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;"><strong><span style="color: #008781; font-size: 16px;">学习方法</span></strong></p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">理论篇部分推荐每天学习2课时,可以在公交地铁上用手机进行学习。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">实战篇部分推荐对照视频,使用配套源码,一遍联系一遍学习。</p> <p style="color: #676767; font-size: 14px; background-color: #ffffff;">课程内容较多,不要一次性学太多,而是要循序渐进,坚持学习。</p> <p><img src="https://img-bss.csdnimg.cn/202103270814203968.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270814406060.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270814503536.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270814594202.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270815088045.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270815261029.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270815411575.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270815499881.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270816008070.jpg" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202103270816139898.jpg" alt="" /></p>
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值