我把JVM的类加载器整理了一下

我把JVM的类加载器整理了一下

作者:良许Linux 2020-07-23 07:26:49

开发

后端

虚拟化 学习JVM这个新的技术,我也分为了3个板块来学习:JVM类加载器,JVM内存结构,JVM垃圾回收这三个板块来学习,今天这篇文章讲的是JVM类加载器。

之前去面试的时候面试官问了我关于关于JVM性能调优的问题,由于自己之前公司的项目里自己没有接触到JVM性能调优的相关问题(感觉这些都是公司架构师考虑的问题),所有面试官问的时候自己一脸懵逼,所有最后的结果当然是凉凉。。,于是,为了查漏补缺,就去学习了一下JVM的相关知识,希望能帮助到大家。

[[334689]]

​ 在学习任何一项新的知识之前,我都会先列出一份学习大纲,然后按照这个学习大纲一步一步的来学习了解,所以学习JVM这个新的技术,我也分为了3个板块来学习:JVM类加载器,JVM内存结构,JVM垃圾回收这三个板块来学习,今天这篇文章讲的是JVM类加载器。

1. 什么是JVM

​ 既然是学习关于JVM的相关理论知识,我们当然得知道什么是JVM。JVM是Java Virtual Machine(Java虚拟机)的缩写。既然说到虚拟机,可能又会有人问什么是虚拟机了,我这里把虚拟机得相关概念放在这里:

  • 虚拟机:就是一台虚拟的计算机,他是一款软件;用来执行一系列计算机指令。虚拟机可以分为系统虚拟机和程序虚拟机。
  • 系统虚拟机:比如VMware,他们完全是对物理计算机的仿真,提供了一个可运行完整操作系统的软件平台。

程序虚拟机:比如Java虚拟机,它专门为执行单个计算机程序而设计。在Java虚拟机中执行的 指令我们称为Java字节码指令。(JVM是运行在操作系统之上的,它与硬件没有直接的交互)

所以根据定义,我们可以得知JVM是程序虚拟机。那么JVM在哪里呢,其实,我们在最开始学习Java得时候,都必须按照Java得运行环境,从网上下载JDK安装包,安装完成之后,在安装路径下会有两个文件夹,一个叫Jdk,一个叫jre,而java虚拟机就在jre的文件夹里面。

​ 存在即有他存在的道理,那么JVM的存在有什么用呢?他是用来干嘛的呢?学过JAVA的都知道,java程序要想运行,Java源程序(.java)要先编译成与平台无关的字节码文件(.class),然后字节码文件再解释成机器码运行。而解释得这个过程就是通过Java虚拟机来执行的(可以参考下面这张图理解)。java虚拟机是来解释字节码文件的,而解释得这个过程其实是一个很复杂得过程,所以这就到了我们今天要讲得主题了。

2. 类加载(classLoading)

​ 我们先来了解一下类加载得整个过程。从下图可以看到类的生命周期一共分为5个阶段,加载、连接(包括验证、准备和解析)、初始化、使用(类得实例化)、卸载(垃圾回收)。

​在Java代码中,我们都知道类(指的是类本身Class,比如,Interface,Enum)的加载、连接、初始化过程都是在程序运行期间完成的。下面我们就先讲一下类得加载、连接和初始化。

类的加载:*最常见的一种情况*是将已存在的类的Class文件(也就是字节码文件)从磁盘上面加载到内存里面,将其放在运行时数据区的方法区中,然后在内存中创建一个java.lang.Class对象用来封装类在方法区中的数据结构

类的连接(又细分了三个阶段):

  • ​ 验证:确保被加载类的正确性
  • ​ 准备:为类的静态变量(也可以称为类变量)分配内存,并将其初始化为默认值(比如int 的默认值就是0)
  • ​ 解析:将类中的符号引用转换为直接引用

类的初始化:为类的静态变量进行赋值(从代码从上到下执行)

Java程序对类的使用方式可分为两种:

  • 主动使用
  • 被动使用

所有的Java虚拟机实现,在每个类或接口被Java程序”首次主动使用”时才初始化他们,一定要记住,是首次并且还是主动使用得时候才会初始化类。

如果对其类或者接口主动使用导致初始化了(此时的初始化就说明加载、连接(连接的三个步骤,注意,此时的连接只完成类的静态变量分配内存,并将其初始化为默认值)已经完成了)

我这里总结了7种主动使用:

  • 创建类的实例
  • 访问某个类或接口的静态变量,或者对该静态变量赋值
  • 调用类的静态方法
  • 反射(如class.forName())
  • 初始化一个类的子类
  • Java虚拟机启动时被表明为启动类的类
  • JDK1.7开始提高的动态语言支持;

除了以上7种情况,其他使用Java类的方式都被看做是对类的被动使用,都不会导致类的初始化。

3. 类的加载连接初始化详细讲解

​ 其实我们知道类的加载的最终产品是位于内存中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

根据以上的总结,我们知道类的连接其实就是当类被加载后,就进入连接阶段。连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行环境中去。那么类的验证的内容有哪些呢?

  • 类文件的结构检查
  • 语义检查
  • 字节码验证
  • 二进制兼容性的验证

4. 类加载器

​ 类的加载其实是类加载器去完成的,我们可以把类加载器想象成一个小人,帮助JVM干活的。那么类加载器的定义是什么呢,这里按照我个人的理解总结了一下:

类加载器(classLoader):类加载器是用来把类加载到Java虚拟机的内存空间中(加载类的工具,类一定是由类加载器去加载)。从JDK1.2版本开始,类的加载过程采用双亲委托机制。这种机制能更好的保证Java平台的安全。在此委托机制中,除了Java虚拟机自带的根类加载器之外(因为根类加载器本身是没有父加载器的),其余的类加载器都有且只有一个父加载器。当Java程序请求加载器loader1加载Sample类时,loader1首先委托自己的父加载器去加载Sample类,若父加载器能加载,则由父加载器完成加载任务,否则才有加载器loader1本身加载Sample类。

类加载器分为两种类型:

(1) Java虚拟机自带的加载器

  • 根类加载器(BootstrapClassLoader),也称启动类加载器
  • 扩展类加载器(ExtensionClassLoader)
  • 系统(应用)类加载器(SystemClassLoader或者AppClassLoader)

(2) 用户自定义的类加载器

  • java.lang.ClassLoader的子类(所有用户自定义的类加载器都应该继承抽象类ClassLoader类)
  • 用户可以定制类的加载方式

类加载器并不需要等到某个类被”首次主动使用“时再加载它

5. 类加载器双亲委托机制详解

​ 这一小节我们来详细了解一下类加载器的双亲委托机制。父亲委托机制也称为双亲委托机制(我个人得理解实际上应该叫做父亲委托机制,因为在源码里面是parent而不是parents):在父亲委托机制中,各个加载器按照父子关系形成了熟悉结构(逻辑上的,比如下图),除了启动类加载器之外,其余的类加载器都有且只有一个父加载器。

以下几种加载器从表面看是继承关系,实际上是包含关系哦

我举例来看看父亲委托机制的实际执行:

​ 对上图执行流程我详细得解释一下类加载器父亲委托机制具体是怎么执行得:首先loader1和loader2是我们自定义的加载器,loader1尝试去加载Sample类,根据父亲委托机制,其实并不是由loader1去直接加载Sample类到虚拟机当中,相反,它是把这个加载任务转交给系统类加载器去完成,系统类加载器再把这个加载任务转交给扩展类加载器,然后扩展类加载器再转交给根类加载器去完成,由于根类加载器已经是类加载器体系层次的最顶层,所以根类加载器会尝试去Sample类到虚拟机当中(然后根类加载器不能加载,因为他是从特定的几个目录去加载),既然根类加载器无法完成加载,他就会把这个任务返回给扩展类加载器(同理,原则上也不能加载),再让系统类加载器去加载(一般是可以加载成功)。最终再把这个流程返回给loader1,就宣告类加载过程结束。

6. 获取类加载器的几种途径

​ 既然我们了解了类加载器的种类,那我们也需要了解通过什么方式可以获取到类加载器,获取类加载器的方式我这里总结了4种方式:

第一种:获得当前类的ClassLoader:

  1. ​ clazz.getClassLoder() 

具体实现如下所示:

  1. Class<?> clazz1 = Class.forName("java.lang.String"); 
  2. System.out.println(clazz1.getClassLoader()); 

第二种:获得当前线程上下文的ClassLoader:

  1. ​ Thread.currentThread().getContextClassLoader(); 

具体实现如下所示:

  1. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 
  2. System.out.println(contextClassLoader); 

第三种:获得系统ClassLoader:

  1. ​ ClassLoader.getSystemClassLoader(); 

第四种:获得调用者的ClassLoader

  1. ​ DriverManager.getCallerLoader() 

​ 我们还需要知道其实数组并不是由类加载器加载创建的的,而是当被需要时,被jvm运行时自动创建的,对于数组来说,他的类加载器是和他元素的类型的类加载一样的,如果元素类型是基本类型,则数组没有类加载器

​ ClassLoader类本身默认是并行加载的的(parallel capable),如果子类想支持并行加载,是需要自己注册的,用户自定义加载器若需要并行加载,需要自行配置,通过调用registerAsParallelCapable()

7. 总结

​ 通过以上得相关总结,我们其实可以发现,JVM学习并不是像spring,springcloud都是应用框架,是可以马上做东西的,立竿见影,可以马上看到效果,JVM不是这样的,涉及到了很多理论。很多同学可能觉得不重要,感觉学了也没有,其实不然,就像练武一样,只有你的内功修炼好了,再去练其他的招式就会很容易,才会精益求精,而JVM就相当于内功,所以可想而知,对于JVM的学习,显然是很重要的。

以上就是我对JVM类加载器相关总结,下一篇文章应该是推出关于结合java源码理解类加载器得相关内容,当然后续也会推出JVM其他板块相关知识得相关总结。

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/228654.html<

(0)
运维的头像运维
上一篇2025-04-18 09:56
下一篇 2025-04-18 09:58

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注