欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

不要再死记硬背Java的类加载啦

程序员文章站 2022-08-29 14:38:27
作为一个程序员,面试的时候都绕不过JVM,可以说这是我们永远的痛。是不是感觉每次面试的时候,都要重新背一下,不然面试会被虐惨。那么问题就来了,为什么每次面试都要背?为什么背完过了断时间就忘了?除了记忆不深刻,还有一个重要原因是没理解,不理解的东西当然记不久。所以从这篇开始,我们要开始学习JVM,争取做到理解记忆,将知识点串起来。虽然这块知识很无聊,很枯燥,但是我争取写的简单,有趣点,我们一起加油,好吗?一、类加载机制1.1完整流程(简单版)从上图中我们可以看到,一个简单的Ja.....

不要再死记硬背Java的类加载啦

作为一个程序员,面试的时候都绕不过JVM,可以说这是我们永远的痛。是不是感觉每次面试的时候,都要重新背一下,不然面试会被虐惨。

那么问题就来了,为什么每次面试都要背?为什么背完过了断时间就忘了?除了记忆不深刻,还有一个重要原因是没理解,不理解的东西当然记不久。

所以从这篇开始,我们要开始学习JVM,争取做到理解记忆,将知识点串起来。虽然这块知识很无聊,很枯燥,但是我争取写的简单,有趣点,我们一起加油,好吗?

不要再死记硬背Java的类加载啦

一、类加载机制

1.1完整流程(简单版)

不要再死记硬背Java的类加载啦

从上图中我们可以看到,一个简单的Java程序执行流程如下:

1.我们本地编写Java代码

2.编译器帮我们自动编译成.class文件(也可以通过javac命令手动编译,因为这边idea帮我们做了,实际上底层还是调用javac命令)

3.接着,部署到web容器中运行(也可以通过java -jar命令来运行)

这个过程感觉很简单,其实就是将Java的源文件转化成Java认识的.class文件,然后打包运行。

1.2完整流程(复杂版)

其实类从第二步(编译成.class文件)到第三步(运行),这个整个生命周期并不是一两句能说清的。其包括复杂且完整的流程:(是不是被骗了,一看下面的图,好复杂,头晕????)

不要再死记硬背Java的类加载啦

 

 

加载(Loading)阶段很简单,当程序执行到需要的类时,JVM就会通过类加载器 将其加载到内存中。接下来,我们先看下什么是类加载器,然后详细讲解整个类加载流程。(稍后再来)

2 类加载器

Java虚拟机设计团队将加载这个动作放在Java虚拟机外面去实现,以便程序能够自己决定何时去获取所需的类。完成这个动作的代码被称为“类加载器”。

以上简单来说,完成加载这个过程的代码叫做类加载器,其有应用程序自己决定。

不要再死记硬背Java的类加载啦

类加载器分为3类:

  1. Bootstrap ClassLoader (启动类加载器)主要负责加载 JDK 安装目录下的核心类库(比如/lib目录下的类),这些核心类库是JVM运行时自身需要用到的。
  2. Extension ClassLoader(扩展类加载器)主要负责加载 JDK 安装目录下的扩展类库(比如/lib/ext目录下的类)。
  3. Application ClassLoader(应用类加载器)负责加载用户自己开发的Java类。

上面的三种类加载器是为了给不同的类加载用的,也就是一个类只能有且只有一个类加载器对其进行加载。

 

3双亲委派机制

那么问题就来了,如何保证只有一个类加载器加载呢?

我们先看下他们的之间的关系:(首先启动类加载器是爷爷,扩展类加载器是爸爸,应用程序类加载器是儿子),除了启动类加载器没有父级,其他的类加载器都有父级。

不要再死记硬背Java的类加载啦

官方说法

如果一个类加载器收到类加载请求,他首先不会自己去尝试加载这个类,而是把这个请求委派父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载器请求都应该传送到最顶层的启动类加载器,只有当父级的类加载器反馈自己无法完成这加载请求,子类加载器才会尝试自己去完成加载

白话翻译下

如果应用程序类加载器(儿子)获取的请求(工资),他不应该自己先花掉,而是先交给他的父级类加载,也就是扩展类加载器(爸爸),这个时候他也不自己花掉,再交给他的父级类加载器,也就是启动类加载器(爷爷)。如果爷爷说无法加载请求(也就是不花钱),再交给扩展类加载器(爸爸),如果爸爸需要花钱,可以花掉(即加载类),如果爸爸不需要花钱,再交给儿子,让儿子花钱。

优点

1.避免类的重复加载,当父亲已经加载了该类时,子类加载器就没有必要再加载一次。

2.避免Java核心api中的类不会被随意替换,规避风险,防止核心API库被随意篡改。

4.破环双亲委派模型

我们需要知道双亲委派机制并不是一个强制性约束模型,只是Java设计者推荐给我们的类加载器的实现方式。

比如Tomcat就没有实现双亲委派模型,我们来思考一下,为什么他没有实现双亲委派模型?(动动脑袋)

不要再死记硬背Java的类加载啦

Tomcat是一个web容器,它需要解决版本隔离的问题。即一个web容器可能需要部署多个应用程序,不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离。

不要再死记硬背Java的类加载啦

图中可以看出:
CatalinaClassLoader和SharedClassLoader自己能加载的类则与对方相互隔离。
WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader 实例之间相互隔离。

很显然,tomcat这种加载机制违背了双亲委派机制模型,它为了实现隔离性,每个 webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器,打破了双亲委派机制。

二、类加载过程

2.1验证阶段

对具体的内容进行校验,确保Class文件的字节流中包含对信息符合Java虚拟机规范的全部要求。其中包括验证文件格式、元数据、字节码、符号引用等各种信息。 

2.2 准备阶段

正式为类中定义的变量分配内存并设置类变量初始值。

2.3解析阶段

实际上是把类的符号引用替换为直接引用的过程。

2.4 初始化阶段

之前说过,JVM会在准备阶段给类的静态字段分配空间和默认值。而在初始化阶段,就会正式执行类的初始化代码,对类进行初始化操作,比如一些从配置中取的信息,并不是直接有默认值,而是通过获取才可以。

2.5 使用阶段

在程序中使用类或对象来执行业务。

2.6 卸载阶段

当确定对象不再需要使用时,JVM需要进行垃圾回收。这里也是重中之重。

 

结语

该篇主要先讲了JVM的类加载器类型,他们是如何配合使用的,为何要破坏类加载器,再描述了文件的完整加载流程,中间配合多张示例图,清楚明了的说明了过程。

如果觉得写得还行,麻烦给个赞????,您的认可才是我写作的动力!

如果觉得有说的不对的地方,欢迎评论指出。也可以关注我的公众号学习Java的小姐姐,我们一起讨论下。

好了,拜拜咯。

参考文献

https://blog.csdn.net/huihuidage/article/details/107425939

 

 

本文地址:https://blog.csdn.net/qq_33774822/article/details/109571290