02|类加载器到底是何方神圣

前面我们分析了,JVM 的整体的一个运行原理

我们首先从“.java”代码文件,编译成 “.class” 字节码文件

然后,类加载器把“.class”字节码文件中的类加载到JVM中,

接着就是JVM 运行我们写好的那些类中代码。

上面就是我们之前的分析类,下面我么着重分析其中的“类加载”过程,看看JVM 的类加载机制到底是怎么样的?

 

 

1、JVM 什么情况下会加载一个类

一个类从加载到使用,一般会经历下面的几个过程:

 

加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载

 

所以,我们得知道,JVM 在执行我们写好的代码过程中,一般什么情况下才会加载一个类?

也就是,啥时候会“.class”字节码文件中这个类到  JVM,其实就是在你使用到这个类的时候。

 

举个例子:

 

public class Kafka {
    public static void main() {
    ReplicaManager  replicaManager = new ReplicaManager();
  } 
}

上面有个类 Kafka.class ,里面有一个 main() 方法作为 主入口。

那么 一旦你的 JVM 进程启动后,它一定会先把你的这个类(Kafka.class)加载到内存,然后从 “main()”方法开始执行。

在 mian() 方法里面,我们明显需要使用 ReplicaManager 这个类去实例化一个对象,此时就必须把 “ReplicaManager.class” 加载到内存里面。

 

简单概括一下就是:

首先代码中包含“main()”方法的主类一定会在JVM 进程启动的时候被加载到内存,开始执行你的“main()” 方法中方的代码,接着遇到使用类别的类,此时就会从对用的“.class” 中加载对应的类到内存中。

 

 

2、 从使用的角度看看,验证、准备和初始化的过程

 

(1)验证阶段

简单的说,这一步就是根据 Java 虚拟机规范,来校验你加载进来的 “.class” 文件中的内容是否符合指定的规范。

 

(2)准备阶段

这个阶段的主要工作就是,给我写好的类中的一些变量分配空间。

 

public class ReplicaManager{
    public static int flushInterval;
}

 

上面的代码,在准备阶段其实就给这个 ReplicaManager 分配一定的内存空间,

然后,给他里面的类变量(也就是static修饰的变量)分配内存空间,来一个默认的初始值。

比如上面的 flushInterval 给一个 “0”的默认值。

 

(3)解析阶段

这个阶段干的事儿,实际上是把符号引用替换为直接引用的过程,其实这个部分的内容很复杂,涉及到JVM的底层,从实用角度而言,对很多同学在工作中实践JVM技术其实也用不到,所以这里大家 就暂时知道有这么一个阶段就可以了。

 

 

 

三个阶段小结:

其实,这三个阶段里,最核心的就是“准备阶段”,因为这个阶段是给加载进来的类分配好内存空间,类变量也分配好内存空间,并且给默认值。

 

(4)核心阶段:初始化

 之前说类,在准备阶段,会给类分配内存空间,

那么什么是类的初始化代码呢?

public class ReplicaManager{
    public static int flushInterval = 
        Configuration.getInt("replica.flush.interval");
    
    static {
        loadReplicalFromDish();
    }
}

如上面这段代码,对于 “flushInterval” ,我们打算通过“Configuration.getInt("replica.flush.interval")”来获取值并赋值给他。这段赋值的代码什么时候会执行呢?

就是在“初始化”阶段来执行。另外,static 静态代码块也会在这一个阶段来执行。

 

什么时候会初始化一个类?

一般来说,有以下时机:

1、通过 new XX() 来实例化类的对象,会触发类的加载到初始化的全过程;

2、包含“main()” 方法的主类,必须是立马初始化的

3、如果初始化一个类的时候,必须先初始化他的父类

 

(5)类加载器

Java 的类加载,简单来说有下面几种

1、启动类加载器

Bootstrap ClassLoader,他主要是负责加载我们在机器上安装的Java目录下的核心类的,JVM启动,那么首先就会依托启动类加载器,去加载你的Java安装目录下的“lib”目录中的核心类库。

 

 

2、扩展类加载器

Extension ClassLoader,这个类加载器其实也是类似的,就是你的Java安装目录下,有一个“lib\ext”目录

 

3、应用程序类加载器

Application ClassLoader,这类加载器就负责去加载“ClassPath”环境变量所指定的路径中的类 其实你大致就理解为去加载你写好的Java代码吧,这个类加载器就负责加载你写好的那些类到内存里。

4、自定义类加载器

除了上面的几种,还可以自定义类加载器,去根据你自己的需求加载你的类

 

(6)双亲委托机制

JVM 的类加载器,是分层级的,启动类加载器是最上层的,扩展类加载器在第二层,第三层是 应用程序类加载器,最下面的是自定义类加载器

image.png

然后基于这个亲子层级架构,就有一个 双亲委托机制

所谓的双亲委托模型:就是 先找父亲去加载,不行的话再由儿子来加载。

这样的话就避免来多层级的加载器结构重复加载某些类。

 

 

 

 

 

 

 

image.png

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值