• java类生命周期,类的“加载,连接,初始化,使用,卸载过程”详解


    “ 如果说核心类库的 API 比做数学公式的话,那么 Java 虚拟机的知识就好比公式的推导过程”

    每本Java入门书籍在介绍Java这门语言的时候都会提到Java跨平台,“一次解释,到处运行的特点“,功臣就是jvm(Java Virtual Machine,Java虚拟机)。

    但是,如果将jvm只与Java语言绑定在一起,那么理解就过于狭隘了,Java虚拟机发展到现在已经脱离了Java语言,形成了一套相对独立,高性能的执行方案。

    除了以上提到的几种语言之外,scala,热门的kotlin都可以运行在jvm上面。

    01 类生命周期

    类从被加载到虚拟内存中开始,到卸载内存为止,它的整个生命周期包括:

    小提示:

    1.加载阶段和连接阶段有时候是交叉进行的,不需要等到完全加载结束。

    2. 解析阶段有时候可以再初始化之后再做。Jvm仅仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要完成对这些符号引用的解析。
    3. 但是这些过程总的开始时间和完成时间都是上图固定顺序。
    4. 这里的“加载阶段”和我们常说的“类加载”是两回事,“类加载”指的是虚线框中三部分加起来。
     

    02 连接(Linking)

    验证:

    当一个类被加载之后,必须要验证一下这个类是否合法,比如这个类是不是符合字节码的格式、变量与方法是不是有重复、数据类型是不是有效、继承与实现是否合乎标准等等。

    我们平常写代码很多时候第一步都是写校验,jvm也是这个思路,Java 编译器生成的类文件必然满足 Java 虚拟机的约束条件,但是为了防止“解字节码注入”。

    准备:

    就是为类的静态变量分配内存并设为 jvm默认 的初值,而不是我们设置的,我们设置的会在后面一个阶段“初始化”期间来做,对于非静态的变量,则不会为它们分配内存。

    jvm默认的初值是这样的:

    基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0。其中boolean只有true,false两种类型,对应到jvm值分别是数据1,0。

    引用类型(对象,数组)的默认值为null。

    构造其他跟类层次相关的数据结构,比如说用来实现虚方法的动态绑定的方法表。

    在 class 文件被加载至 Java虚拟机之前,这个类无法知道其他类及其方法、字段所对应的具体地址,甚至不知道自己方法、字段的地址。因此,每当需要引用这些成员时,Java 编译器会生成一个符号引用。在运行阶段,这个符号引用一般都能够无歧义地定位到具体目标上。

    解析:

    上面说到的“在运行阶段,这个符号引用一般都能够无歧义地定位到具体目标上”,就是在解析阶段进行的符号解析。

    这个阶段目的正是将常量池中的符号引用转换解析成为实际引用。在解析阶段,jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址,从而让用到了别的类或者接口的类能找到和加载其他的类/接口。

    如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的链接以及初始化。)

    03 初始化

    在 Java 代码中,如果要初始化一个静态字段,我们可以在声明时直接赋值,也可以在静态代码块中对其赋值。除了final static修饰的常量,直接赋值操作以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为 < clinit >。

    类加载的最后一步是初始化,目的便是为标记为常量值的字段赋值,以及执行 <clinit > 方法的过程。Java 虚拟机会通过加锁来确保类的 < clinit > 方法仅被执行一次。

    类初始化的触发情况:

    当虚拟机启动时,初始化用户指定的主类(main函数);

    当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;

    当遇到调用静态方法的指令时,初始化该静态方法所在的类;

    当遇到访问静态字段的指令时,初始化该静态字段所在的类;

    子类的初始化会触发父类的初始化;

    如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;

    使用反射 API 对某个类进行反射调用时,初始化这个类;

    当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。

    设计模式中单例延迟加载,便是充分利用了这个特点。

    04 卸载

    那么多的类,什么时候卸载谁呢?关于卸载谁,满足如下条件:

    ·      该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例;

    ·      加载该类的ClassLoader已经被回收;

    ·      该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

    关于什么时候卸载,当以上条件都满足了,垃圾回收时候回在方法区清空类信息进行卸载,英雄迟暮,这个类的一生也就走到了尽头了。

    有错欢迎私我指正


  • 相关阅读:
    C#反射
    做下一周计划
    OFFSET 函数
    微信跳一跳学习笔记
    跳一跳脚本代码搬运
    预测羽毛球赛成绩学习笔记
    将Python123中作业成绩绘制成雷达图
    Matplotlib库
    Numpy库
    第四周作业
  • 原文地址:https://www.cnblogs.com/zengzhiqin/p/12059348.html
Copyright © 2020-2023  润新知