Java - JVM - 类的生命周期

时间:2024-06-28 08:03:55
  1. 概述
    1. 简述 JVM 里 类的生命周期
    2. 上次写了 30%, 居然丢了
      1. 难受, 又要重新写
  2. 类的生命周期
    1. 加载
    2. 使用
    3. 卸载

1. 加载

  1. 概述
    1. 类型的加载
  2. 大体流程
    1. 装载
    2. 连接
      1. 验证
      2. 准备
      3. 解析(可选的)
    3. 初始化
  3. 问题: 为啥解析是可选的
    1. 原因
      1. JVM 规范没有强制规定类型解析的时机
      2. 不是不做, 是说可以在其他的时候做
  4. 问题: 这么关键的机制, 如何触发呢
    1. 时机
      1. 主动实例化
        1. 这个 ps 有讲
  5. 特性: 类加载 与 依赖
    1. 子类 与 父类
      1. 如果子类加载, 则它的所有父类, 必须加载完毕
    2. 接口
      1. 接口没有这种规定

1. 装载

  1. 概述
    1. 由一个二进制流, 得到 方法区 类数据, 和 堆区 的 Class 实例
  2. 基本动作
    1. 获取 二进制流
      1. 结果
        1. 读入完整的二进制流
    2. 解析二进制流, 并填入 方法区
      1. 结果
        1. 解析二进制流为 方法区 格式
        2. 把类型信息, 存在 方法区
    3. 创建 Class 类实例
      1. 结果
        1. 在 堆 里创建引用
        2. 指向 方法区 类型信息
  3. 问题1: 二进制流
    1. 概述
      1. 承载类型信息的二进制数据流
        1. 例如我们常见的 class 文件
    2. 来源
      1. class 文件
        1. 本地文件系统的 class 文件
          1. classpath, 这个我也不大懂
        2. 网络来源
        3. 压缩文件
        4. 数据库
        5. 动态编译
          1. 运行时编译 java 源文件
        6. 动态生成
          1. 运行时生成类的 class 文件
      2. 其他
  4. 问题2: 解析二进制流
    1. 概述
      1. 将 class 文件转化为 方法区 的格式, 然后存在里面
    2. 解析
      1. 通常是按照 class 文件格式解析的
      2. 特殊时候, 也可以按别的格式解析
    3. 方法区
      1. 方法区有自己的结构
      2. 解析后的内容, 按方法区的结构存进去
  5. 问题3: 创建 Class 实例
    1. 概述
      1. 在 堆 里创建 类型对应的 Class 实例
    2. Class 实例
      1. 指向 方法区 的类型信息
  6. 类加载器
    1. 启动类加载器
      1. 时机
        1. jvm 启动
      2. 作用
        1. 加载必须启动类
    2. 自定义类加载器
      1. 时机
        1. 运行时
        2. 主动初始化
      2. 作用
        1. 加载其他类
      3. 关系
        1. 是 启动类加载器 的子类
  7. 机制: 预加载
    1. 概述
      1. 类加载预料某个类型将要使用, 提前加载
    2. 区别
      1. 不是 完整加载
    3. 报错
      1. 如果装载出现了问题
        1. 会在 正式使用时, 才会报错

2. 连接

1. 验证

  1. 概述
    1. 验证 类型信息 是否符合 Java 语义, 以及 安全 等
    2. 这块不是重点, 我就不多讲了
      1. 其实是不懂
  2. 验证内容
    1. 格式
      1. 文件格式
      2. 长度确认
      3. 魔数
    2. 超类
      1. 除了 Object , 谁都有超类
    3. 符号引用
    4. 其他兼容
      1. final 类不能有子类
      2. final 方法不能被覆盖
      3. 确保类型和超类没有不兼容
    5. 其他
  3. 问题: 验证时如果需要其他类, 会触发 类加载吗?
    1. 结果
      1. 不会
        1. 不是主动使用

2. 准备

  1. 概述
    1. 类型信息通过验证, 分配内存
  2. 前提
    1. 主动使用
      1. 这个时候, 通常需要实例
      2. 所以说, 这个是 实例化 前的准备
  3. 分配内存
    1. 变量
      1. 类变量会分配到对应的空间
      2. 并被赋予 默认值
        1. 各种 0, false, null
    2. 方法
      1. 可能会有方发表, 指向每个方法
        1. 特别是 继承的方法, 这样不用搜索超类
          1. 提高效率

3. 解析

  1. 概述
    1. 将 符号引用 换成 直接引用
    1. 因为不懂

3. 初始化

  1. 概述
    1. 初始化
  2. 初始值
    1. 赋值
      1. 通常是 static 值
      2. 类的值
    2. 通过
      1. 类变量初始化语句
        1. static 变量的 赋值语句
      2. 静态初始化语句
        1. 静态代码块
    3. clinit 方法
      1. 来源
        1. 自动生成
      2. 内容
        1. static 复制语句
        2. 静态代码块
      3. 没有?
        1. 如果类型没有 static 内容
          1. 那就没有这个方法
        2. static final 被当做常量
          1. 也没有
    4. 初始化步骤
      1. 如果有超类
        1. 初始化超类
      2. 执行 clinit 方法

      3. 其他
        1. 接口不需要执行超类的 clinit 方法
    5. 多线程
      1. 场景
        1. 多个线程同时触发 类加载
      2. 结果
        1. 第一个执行初始化
        2. 其他全部等待

2. 使用

  1. 概述
    1. 其实就是对象的生命周期
  2. 内容
    1. 实例化
      1. 时机
        1. 类加载完成
      2. 方法
        1. 构造函数
    2. 垃圾回收
      1. 这个以后单独说

3. 卸载

  1. 概述
    1. 类型生命周期的最后
  2. 对象
    1. 自定义装载器装载的类
  3. 时机
    1. 类型 不可触及
      1. 判断
        1. 没有明确引用
        2. 没有 class 类 实例

ps

  1. ref
    1. 深入 Java 虚拟机
  2. 区别: 初始化 与 实例化
    1. 初始化
      1. 类加载的最后一步
    2. 实例化
      1. 类加载完成之后
      2. 结果是一个 类型的实例
  3. 主动使用 和 被动使用
    1. 主动使用
      1. 创建新实例
      2. 调用某个类的 静态方法
      3. 使用某个 类 或者 接口 的静态字段
        1. 除了 final 字段
      4. 反射方法
      5. 初始化某个类的子类
      6. 启动类
        1. 比如 main
        2. 启动时就必须使用
    2. 被动使用
  4. classpath
    1. 寻址用, 但是我不大懂
  5. 对象生命周期
    1. 这个以后可以说说
      1. 实例化
      2. 垃圾收集
  6. 类加载器
    1. 这个以后也可以说说