0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

jvm的类加载器的整体结构及过程解析

454398 来源:it610 作者:H.U.C-王子 2020-09-27 15:49 次阅读

前言

我们很多小伙伴平时都是做JAVA开发的,那么作为一名合格的工程师,你是否有仔细的思考过JVM的运行原理呢。

如果懂得了JVM的运行原理和内存模型,像是一些JVM调优、垃圾回收机制等等的问题我们才能有一个更清晰的概念。

为了走进JVM,深入了解底层,王子打算写一个JVM的专题,留下自己对JVM探索的足迹,同时也希望能帮到小伙伴们更好的理解JVM。

那我们开始吧。

JAVA代码的运行流程

首先我们就来聊一聊JAVA代码是怎么运行起来的,这部分比较基础相信大家都知道,就当成是个复习吧。

我们编写的代码都是在java文件中编写的,然后会编译成class字节码文件。

当我们使用到哪个类的时候就会通过类加载器把class字节码文件中的类加载到jvm内存中,然后就是在jvm内存中运行我们的代码了。

整体的运行流程就是这样,相信小伙伴们都很清楚这些,但是有关类加载器是如何把类加载到jvm内存中的,小伙伴们有考虑过吗?

今天我们主要就是聊这一部分。

JVM什么时候加载类

其实说到类加载的底层机制,这是一个很复杂的过程,但是对于我们平时的工作来讲,只要懂得它的核心原理就可以了。

一个类的加载过程会经历如下的几个过程:

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

首先我们就先弄明白一个问题,jvm是什么时候去加载类的呢?

其实答案很简单,就是我们什么时候使用到了这个类,它就去class字节码文件中去加载这个类。

而作为程序的入口,具有main方法的类,肯定是最开始的时候就加载到jvm中了。

对于加载类的时间点问题,其实就是这么简单。

类加载器和双亲委派机制

既然我们知道了类加载的时间点,那么jvm是通过什么方式对类进行加载的呢?就是类加载器。

那接下来我们就来聊聊jvm的类加载器。

jvm的类加载器总体上可以分成4层,我们一起看一下。

1.启动类加载器

首先就是jvm启动的第一道关口,启动类加载器Bootstrap ClassLoader,它主要是加载java的核心类。

相信大家都知道,无论是什么环节下运行java程序,都是要安装jvm虚拟机环境的,而在这个环境的目录中是有一个lib文件夹的,这个文件下就是java最核心的类库,支撑着java系统的运行。

所以一旦jvm启动,那么首先就会通过启动类加载器去加载lib文件夹下的核心类库。

2.扩展类加载器

然后我们就到了第二层,扩展类加载器Extension ClassLoader,这个类加载器其实与启动类加载器是类似的。

在我们的jvm虚拟机环境目录下,是有一个lib/ext的文件夹的,这里面的类就是java运行环境的一些扩展类,这些扩展类就是在jvm启动后,通过扩展类加载器进行加载的。

3.应用程序类加载器

加载完核心类库和扩展类,这时候就到了第三层,应用程序类加载器Application ClassLoader,这个类加载器你就可以理解成是加载我们写好的java代码的就可以了。

4.自定义类加载器

前面的三层就是基本的类加载器了,然后第四层是自定义类加载器,根据一些特殊的需求来自己定义类加载器加载我们的类。

整体上类加载器就是这么的4层结构。很多小伙伴可能都听说过双亲委派机制,那么什么是双亲委派机制呢,王子就和大家用最接地气的语言描述一下。

其实很好理解,就是当我们的类加载器要加载一个类的时候,它首先会委派给它的父亲去加载,但是如果它的父亲没找到就会把这个事交给他的孩子自己去完成了。

这就是双亲委派机制。

举个例子,假如我们的应用程序类加载器要加载一个类A,那么首先它会先回家找它老爸扩展类加载器,问问“老爸,你那有这个类A吗?”

然后扩展类加载器接到这个请求之后,同样也懒得处理,再去找它爷爷启动类加载器。

它爷爷找了一圈没找到类A,很生气,就对扩展类加载器说,“我这没有,你自己找去!”

然后扩展类加载器就灰溜溜的自己找了一圈,同样也没找到,这时候就找到应用类加载器了,说:“我这哪有你这个类A,这明明是你自己应该干的活,爱上哪找上哪找去,我不管了”。

这时候应用类加载器就只能自己去处理了,找了一圈发现找到了类A,就把它加载到jvm内存中了。

相信大家看了这个例子应该很容易理解了吧。

所以假设我们自己创建了一个类java.lang.String,它是不会被应用类加载器加载到内存中的,因为父类中可以找到这个类,就直接给加载到内存中了。

聊聊验证、准备、解析、初始化阶段

聊完了加载,我们再来看看验证、准备、解析、初始化这几个阶段jvm都做了什么。

1.验证阶段

这一步其实很容易理解,就是jvm根据java规范,来校验你加载进来的class文件中的内容是否符合规范,如果不符合规范jvm是无法正常运行的。

所以在加载后,首先就是验证阶段。

2.准备阶段

假设我们有一个类A,刚刚加载并通过了验证,那么就会进行准备工作。

这个准备工作其实就是给类A分配一定的内存空间,然后给里面的静态变量(static修饰的变量)也分配内存空间,并赋初始值。

3.解析阶段

这个阶段干的事实际上是把符号引用替换为直接引用,这一过程网上有很多资料,还是比较复杂的,如果感兴趣小伙伴们可以自己查阅一下资料。

实际工作中也很少会接触这部分的内容,所以我们知道有这么个阶段就可以了。

4.初始化阶段

在准备阶段,我们把类A的内存已经分配完了,那么初始化阶段要做些什么事呢?我们先看一下类A的代码

public class A {
    private static String i=System.getProperty("i");
}

准备阶段我们只是给变量i分配了内存空间,并赋值了初始值,但是后边的System.getProperty("i")是不会执行的。

没错,这部分代码就是在初始化阶段执行的,另外静态代码块也会在这一阶段执行。

举个例子,比如我们新建一个对象new A(),此时就会触发从加载到初始化的全过程,把这个类准备好并创建一个实例对象。

此外这里有一个规则,如果类A继承了类B,那么在初始化类A的时候,如果发现类B还没有初始化,会先初始化类B。

扩展

到这里关于JVM的类加载机制其实就已经说完了,王子再给大家扩展一个小知识点。

小伙伴们想过没有,Tomcat也是用java开发的,那么它的类加载机制是什么样的呢,为什么就能支持jsp呢?

其实它就是利用了自定义类加载器这一机制,自己自定义了很多类加载器,整体的结构如下:

Tomcat自定义了这么多的类加载器,用来加载它自己的核心类库,并且Tomcat是打破了双亲委派机制的,感兴趣的小伙伴可以自己去查资料了解一下,王子就不在本篇文章长篇大论来聊Tomcat了。

总结

今天我们聊的内容还是jvm中比较基础的部分,以后的文章我们再慢慢深入,去探索jvm的底层原理,如果对JVM感兴趣的小伙伴可以关注王子的后续文章哦,我们可以一步一个脚印的逐步分解JVM,去了解JVM的垃圾回收机制、性能调优等等实用性问题,让你面对JVM的面试或者生产实践也可以游刃有余。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2967

    浏览量

    104739
  • JVM
    JVM
    +关注

    关注

    0

    文章

    158

    浏览量

    12223
  • 类加载器
    +关注

    关注

    0

    文章

    6

    浏览量

    930
收藏 人收藏

    评论

    相关推荐

    PyTorch 数据加载与处理方法

    ,数据加载主要依赖于 torch.utils.data 模块,该模块提供了 Dataset 和 DataLoader 两个核心。 1.1 Dataset Dataset 是 P
    的头像 发表于 11-05 17:37 399次阅读

    6网线结构特点有哪些

    网线(CAT6)是网络线缆的一种,其结构相对于五线和超五线来说更为复杂,以提供更好的传输性能和抗干扰能力。以下是六网线
    的头像 发表于 09-06 09:58 808次阅读

    只读存储的基本结构和工作过程

    只读存储(Read-Only Memory,ROM)是一种重要的计算机存储设备,它以非破坏性读出方式工作,即只能读出存储的信息而无法直接写入新的信息。这种特性使得ROM在存储固定程序和数据方面具有独特的优势。下面将详细阐述只读存储的基本
    的头像 发表于 09-05 10:43 949次阅读

    从原理聊JVM(一):染色标记和垃圾回收算法

    更好地优化自己的代码,并解决一些潜在的性能问题。 本文及后续文章将从原理聊起,对JVM的内存分配、GC、编译等知识进行分析和总结。 1 JVM运行时内存划分 1.1 运行时数据区域    • 方法区 属于共享内存区域,存储已被虚拟机
    的头像 发表于 08-20 15:25 239次阅读
    从原理聊<b class='flag-5'>JVM</b>(一):染色标记和垃圾回收算法

    labview CAN DBC加载解析程序

    labview CAN DBC加载解析程序
    发表于 08-18 11:42

    聊聊JVM如何优化

    进行优化。 1.JVM内存模型 针对JAVA8的模型进行讨论,JVM的内存模型主要分为几个关键区域:堆、方法区、程序计数、虚拟机栈和本地方法栈。堆内存进一步细分为年轻代、老年代,年轻代按其特性又分为E区,S1和S2区。关于内存
    的头像 发表于 08-05 17:49 475次阅读
    聊聊<b class='flag-5'>JVM</b>如何优化

    增强型MOS管的结构解析

    增强型MOS管(Enhancement MOSFET)是一种重要的场效应晶体管,具有高输入阻抗、低输入电流、高速开关和低噪声等优点,被广泛应用于电子设备中。以下是对增强型MOS管结构的详细解析
    的头像 发表于 07-24 10:51 1526次阅读

    卷积神经网络的基本结构和训练过程

    处理具有空间层次结构的数据时表现出色。本文将从卷积神经网络的历史背景、基本原理、网络结构、训练过程以及应用领域等方面进行详细阐述,以期全面解析这一重要算法。
    的头像 发表于 07-02 18:27 877次阅读

    PLC基本结构解析

    方式和便捷的编程方式,被广泛应用于各种工业控制系统中。本文将详细解析PLC的基本结构,包括其主要组成部分的功能和特点,以便读者对PLC有更深入的了解。
    的头像 发表于 06-25 14:30 966次阅读

    解析经典蓝牙设备连接过程

    应用中,蓝牙设备发现、连接、断开等使用场景较为常见,其中设备连接是至关重要的一环,它涵盖了设备之间建立连接的整个过程。本文将对经典蓝牙设备连接过程进行解析,带大家一起了解连接的整个过程
    的头像 发表于 06-05 09:11 2237次阅读
    <b class='flag-5'>解析</b>经典蓝牙设备连接<b class='flag-5'>过程</b>

    并行加载8位寄存数据表

    电子发烧友网站提供《并行加载8位寄存数据表.pdf》资料免费下载
    发表于 05-22 09:41 0次下载
    并行<b class='flag-5'>加载</b>8位寄存<b class='flag-5'>器</b>数据表

    【AWTK使用经验】加载和释放外部图片

    AWTK是基于C语言开发的跨平台GUI框架。《AWTK使用经验》系列文章将介绍开发AWTK过程中一些常见问题与解决方案,例如:如何加载外部资源?如何设计自定义进度条?这些都会在系列文章进行解答。加载
    的头像 发表于 04-26 08:25 473次阅读
    【AWTK使用经验】<b class='flag-5'>加载</b>和释放外部图片

    鸿蒙原生应用开发-ArkTS语言基础库概述

    线程之间进行通信,开发者需要主动创建和关闭Worker线程。 2.提供常见的容器库增、删、改、查的能力。 3.提供XML、URL、URI构造和解析的能力。 XML被设计用来传输和存储数据,是一种可
    发表于 03-05 15:42

    ArkTS语言基础库-解析

    多线程并发,支持Worker线程和宿主线程之间进行通信,开发者需要主动创建和关闭Worker线程。 提供常见的[容器库增、删、改、查]的能力。 提供XML、URL、URI构造和解析的能力。 XML
    发表于 02-20 16:44

    在BF707开发过程中向Flash烧写一段代码,然后断电进行加载,发现并未加载成功如何解决?

    在BF707开发过程中向Flash中烧写过一段代码,然后断电进行加载,发现并未加载成功,当进行如下操作却失败】 1.利用CCES仿真,在debug情况下对JTAG进行Test结果为
    发表于 01-12 06:03