浅谈 JVM 类加载机制

1 篇文章 0 订阅

开篇

本文是对过往笔记的一些整理,如有不对,欢迎指导。

Java 代码如何跑起来的

我们平时写的代码都是以 .java 为后缀结尾的文件。而我们部署应用时,要么是打成 jar 包, 通过
java -jar的命令运行;要么打成 war 包, 直接丢到 tomcat 等 web 容器中,然后启动 web 容器。这样我们的 Java 应用就算是跑起来了。

那么从打包-> 运行这中间到底发生了什么?

  • 首先想到就是编译源文件得到 .class 结尾的字节码文件

  • 然后就是把这些字节码文件打成 jar 包

  • 紧接着使用 java 命令运行 jar 包,此时就会启动一个 jvm 进程

  • 最后 jvm 进程会负责管理运行字节码文件

进入正题

在上一段末尾,有提到 jvm 会接手字节码文件,保证代码得以运行使用。那么 jvm 是如何做的呢?

这时就需要引入一个概念 - JVM 的类加载机制。这也是一个常见的面试题。

类加载过程

先来笼统的说下一个类从加载到使用所经历的过程

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化
  6. 使用
  7. 卸载

其中,验证,准备,解析 合在一起称为 连接阶段

详细说一下

下面会针对其中几个重要阶段逐个进行说明

加载

问:JVM 什么时候会去加载一个类?

答:当然是,用到的时候。

JVM 进程启动后,一定会先加载指定的主入口类,然后从 main 方法开始执行。

比如下面的代码,当 App.class 被加载到内存后,随即开始执行 main 函数时,此时需要实例化 User 类,所以这个 User 类也会被加载到内存中去。

public class App {
    
    public static void main(String[] args) {
        User user = new User();
    }
    
}

讲到这里就大概知道了,所谓加载过程就是将对应的字节码文件加载到内存中去。

验证

确保 加载的类信息 符合 Java 虚拟机规范,避免产生安全性问题。

所谓这个规范,简单来讲就跟英语语法一样,语法用不对,你想表达的语义别人就听不明白。万一产生歧义,会被打的。

准备

为类变量分配内存并设置初始值

当 App.class 被加载到内存中后,紧接着验证内容符合规范后,就需要给 App 中的类变量分配内存空间。

比如下面代码中的 num 变量,在准备阶段,他就会被赋一个初始值 0

public class App {
    
    // 定义一个类变量
    public static int num;
    
    public static void main(String[] args) {
        // User user = new User();
    }
    
}
解析

把类的二进制数据中的符号引用替换为直接引用。这个确实听起来比较复杂,涉及到一些底层的相关知识。先不用细究。

有句话说的好,可以xx,但是没必要!!!

初始化

对于以下代码,前面 ‘准备’ 阶段有说到,会给 num 赋一个初始值 0,

public class App {
    
    // 定义一个类变量
    public static int num;
    
    public static void main(String[] args) {
        // User user = new User();
    }
    
}

那么对于如下代码,通过调用一个工具类求得的和什么时候会赋值给 num 这个类变量呢?

结论就是 初始化 阶段,另外静态代码块也是在这个阶段执行的。

public class App {
    
    // 定义一个类变量
    public static int num = NumberUtil.sum(1, 2);
    
    public static void main(String[] args) {
        // User user = new User();
    }
    
}

jvm 类加载器以及双亲委派模型

上面描述的一些列过程都是由一个叫 类加载器 的东西来实现的。

而类加载器又分为以下几种:

  • BootstrapClassLoader(启动类加载器)

负责加载 jdk 安装目录下面的 lib 目录下的核心类库。

  • ExtensionClassLoader(扩展类加载器)

在 lib 目录下,还有一个 ext 目录,这里面有些类就需要这个类加载器来加载。

  • ApplicationClassLoader

我们在配置 java 环境变量时,一般会配一个 ClassPath,这个ClassPath 所指的路径里面类是由该类加载器加载的。

  • 自定义类加载器

最后一种就是自定义类加载器,我们可以根据需要去决定是否自定义这样一个类加载器。

双亲委派模型

当你的应用程序需要加载一个类时,它会先委派给自己的父类加载器去加载,最终通过一层层传导至最顶层。

如果父类加载器没找到这个类,就会往下寻找子类加载器去加载。

图释如下:
在这里插入图片描述

总结

关于 jvm 类加载机制,本文只是做了简单的入门总结。里面有很多点没有展开来讲,甚至一些难点也只是简单提了一下。后续会继续补充~~

冰冻三尺非一日之寒,要想把上面的知识牢记于心,不是一件易事, 需要花很多时间理解和总结。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值