十一.吊打面试官系列-JVM优化-深入JVM类加载机制

news2024/11/22 13:44:18

前言

从本篇文章开始我们来探讨JVM相关的知识,内容附带JVM的启动,JVM内存模型,JVM垃圾回收机制,JVM参数调优等,跟着文章一步一步走相信你对JVM会有一个不一样的认识,如果觉得文章对你有所帮助请给个好评吧。

JVM类加载系统

1.JVM的启动流程

当我们编写好Java源代码之后如hello.java ,通过javac命令把hello.java文件编译为hello.class文件,然后通过java.exe去执行hello.class 字节码文件,这个时候Java会启动JVM虚拟机,虚拟机是通过jvm.ddl文件创建的,底层是由C++实现的,具体的启动流程如下
在这里插入图片描述
对上图做一个步骤解释:

  1. 编译源代码:使用Java编译器(javac)将Hello.java编译成字节码文件(Hello.class)。这一步将源代码转换成JVM能够理解的指令集。
  2. 启动JVM:通过命令行界面调用java.exe来启动Java虚拟机(底层是由C++来实现的),java.exe是JVM的入口点,负责加载和运行Java应用程序。
  3. 创建启动类加载器:JVM在启动时,会首先加载BootstrapClassLoader启动类加载器(这个类加载器也是c++实现的),它是Java类加载器体系的最顶层加载器,负责加载核心类库。
  4. 创建启动器:启动类加载器会加载Launcher , C++会调用Java代码创建JVM启动器:sun.misc.Launcher ,该启动器的作用是用来加载器其他的类加载器,比如:AppClassLoader应用类加载器
  5. 加载应用类:Launcher 会根据当前类Hello.class找到其ClassLoader并加装它,也就是AppClassLoader应用类加载器,它负责加载用户自定义的Java类(如Hello类)
  6. 加载Class : 通过AppClassLoader 加载Hello.class字节码文件
  7. 执行Main方法:找到class类中的main方法,JVM通过调用类的main方法作为程序的入口点来执行Java程序(这一步也是c++调用的)
  8. 运行Java程序:Java程序开始执行,直到遇到main方法结束或者发生异常而终止。

2.类加载器

当我们在Java中编写代码并引用某个类时,这个类是如何被加载到JVM中的呢?这涉及到JVM的类加载器(ClassLoader)以及类加载的流程和双亲委派机制。下面我将详细解释这些概念。

JVM的类加载器是负责将类的字节码文件(通常是.class文件)加载到JVM中,并为其生成对应的Class对象的过程。类加载器是Java运行时环境的一部分,是Java程序获取字节码文件的重要途径。

在这里插入图片描述

JVM提供了三种主要的类加载器:

  • 引导类加载器(Bootstrap ClassLoader):这是JVM的内置类加载器,主要负责加载Java的核心类库,一般对应JAVA_HOME/lib 目录中的JAR包,如java.lang.*、java.util.*等。由于它并不是Java类库的一部分,而是JVM自身的实现,所以它并不继承自java.lang.ClassLoader。
  • 扩展类加载器(Extension ClassLoader):这是Java的标准扩展类加载器,负责加载Java的扩展类库,一般对应JAVA_HOME/lib/ext目录中的JAR包。它是java.lang.ClassLoader的子类,由sun.misc.Launcher$ExtClassLoader实现。
  • 应用类加载器:Application ClassLoader:也称为系统类加载器(ApplicationClassLoader)或默认类加载器(System ClassLoader),负责加载应用程序的类路径(classpath)下的所有类包括pom.xml导入的jar。它是java.lang.ClassLoader的子类,由sun.misc.Launcher$AppClassLoader实现。在Java应用程序中,我们通常使用的就是这个类加载器。

除了以上三种主要的类加载器,我们还可以自定义类加载器,通过继承java.lang.ClassLoader类并重写其相关方法来实现。

注意:这些类加载器并没有实际上的继承关系

3.双亲委派机制

JVM的双亲委派机制是Java语言服务器级别的安全策略,主要思想是在类加载过程中,子类委托给父类加载器优先加载,即:当一个类需要被加载时,它首先会委托给其父类加载器进行加载。如果父类加载器无法加载该类,那么子类加载器才会尝试自己加载,如果父类加载过了子类就不会再加载了。这种层层委派的方式确保了类加载的有序性和唯一性
在这里插入图片描述
双亲委派的好处在于:

  1. 类加载安全策略:例如我们自己编写一个 java.lang.String 是否会覆盖java自带的String类呢?答案是无法覆盖,因为BootStrapClassLoader优先加载了java.lang.String 后,AppClassLoader在加载我们自己的java.lang.String的时候会检查重复加载,也就不会再加载了。保证了类的唯一性
  2. 保证有序性 : JVM启动必须要加载一些基础的类,比如:Object.clas 这些基础的类会通过BootstrapClassLoader 和 ExtClassLoader 优先加载后,再加载我们自己的类,否则JVM无法启动,启动也会报错。

下面是AppClassLoader的类加载源码,可以看得出来JVM在加载类之前会查找类是否已经被加载,如果没加载就会调用 parent.loadClass 让父类优先加载,如果加载失败再调用findClass自己加载

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
        	//1.首先,检查类是否已加载
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                	//如果父类加载器不为空,则优先委派父类进行加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    	//如果父类加载器为空,则查找 Bootstrap 类加载器,如果找不到则返回null
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
				
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //如果c == null 说明父类加载失败,则自己加载
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }


4.打破双亲委派

在JVM中,类加载器的双亲委派机制是一种默认的行为,它确保了类加载的有序性和安全性。然而,在某些特殊情况下,开发者可能需要打破这种机制来实现特定的功能,例如热部署、插件化开发等。以下是一些打破双亲委派机制的方法:

  1. 自定义类加载器

最直接的方式是创建自定义的类加载器,并在其加载类的过程中不遵循双亲委派机制。这可以通过在自定义类加载器的loadClass方法中直接加载类,而不是先调用父类加载器的loadClass方法来实现。

public class CustomClassLoader extends ClassLoader {  
    @Override  
    public Class<?> loadClass(String name) throws ClassNotFoundException {  
        // 自定义加载逻辑,不调用super.loadClass(name)  
        // ...  
    }  
}

然而,这样做可能会破坏Java的安全模型,因为它允许自定义类加载器加载Java核心库中的类,这可能会导致安全问题。

  1. 使用线程上下文类加载器

在Java中,每个线程都有一个与之关联的上下文类加载器(ContextClassLoader)。这个类加载器可以通过Thread.currentThread().getContextClassLoader()来获取。线程上下文类加载器为Java应用程序提供了一种在运行时动态加载类的方式,而不必受双亲委派机制的限制。

Thread.currentThread().setContextClassLoader(new CustomClassLoader());

然后,可以使用这个上下文类加载器来加载类,而不是使用默认的类加载器。

  1. 使用Java的代理类加载器

在某些情况下,可以使用Java的代理类加载器(如URLClassLoader)来加载类,这些类加载器提供了更多的灵活性来加载类。虽然它们通常遵循双亲委派机制,但可以在必要时被修改或扩展来打破这个机制。

初始之外还有其他的方式比如:使用Java 9的模块化系统(JPMS),但它提供了一种新的方式来管理类的加载和隔离。 ; 或者使用使用OSGi(Open Service Gateway initiative)它提供了自己的类加载器机制,允许不同的模块(bundle)独立地加载和管理类,这个一般我们接触的较少。

需要注意的是,打破双亲委派机制可能会导致类加载和安全性方面的问题。因此,在决定这样做之前,应该仔细考虑其潜在的影响,并确保采取了适当的措施来确保系统的稳定性和安全性。

我们熟知的Tomcat就打破了双亲委派机制,它通过自定义类加载器的方式来实现APP应用加载隔离具体的内容请看《深入源码剖析Tomcat如何打破双亲委派》

5.类加载流程

JVM(Java虚拟机)的类加载流程主要包括:加载,验证,准备,解析,初始化 几个阶段:
在这里插入图片描述
类的加载、验证、准备、解析和初始化这五个阶段通常被称为类的链接(Linking)过程。

  1. 加载(Loading):

    使用到某个类时,JVM会通过类的全限定名查找和加载class文件,并通过IO读入字节码文件,将其加载到JVM中,在方法区(元空间)会存储好class,而在堆内存中会生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

  2. 验证(Verification):

    确保被加载的类的正确性和安全性。包括文件格式验证、元数据验证、字节码验证和符号引用验证。

  3. 准备(Preparation):

    为类的静态变量分配内存,并将其初始化为默认值,比如 static int a = 1 , 在这里会赋初始值 0。这里不包括用final修饰的静态变量,因为final在编译的时候就会分配了,准备阶段会显式赋值

  4. 解析(Resolution):

    把类中的符号引用转换为直接引用。这主要是将类名、字段名、方法名等符号引用转换为指向方法区中的实际内存地址的直接引用,这个过程叫:静态链接,而动态链接是在程序运行期间完成的将符号引用替换为直接引用

  5. 初始化(Initialization) :

    为类的静态变量赋予正确的初始值,也就是第三步准备阶段的今天变量赋正确的初始值(如果有的话)。这个阶段会执行类构造器<clinit>()方法,这是由编译器自动收集类中的所有类变量的赋值动作和静态代码块(static块)中的语句合并产生的。

  6. 使用(Using):

    类的初始化完成后,就可以通过实例化类、调用类的静态方法等方式来使用这个类了。

  7. 卸载(Unloading):

    当类的生命周期结束时,JVM的垃圾回收机制会回收类的内存,这个过程称为类的卸载。但在Java中,类的卸载是由JVM来控制的,开发者通常不需要显式地卸载类。

在这里插入图片描述

文章对你有帮助请给个好评,下一章:JVM优化-深入JVM内存模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1680571.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Mybaties-plus+Vue+elememt 驾校管理系统 设计与实现

一.项目介绍 系统角色&#xff1a;管理员、驾校教练、学员 管理员&#xff1a; 个人中心&#xff1a;修改密码以及个人信息修改 学员管理&#xff1a;维护学员信息&#xff0c;维护学员成绩信息 驾校教练管理&#xff1a;驾校教练信息的维护 驾校车辆管理&…

水离子雾化壁炉与会所房间的氛围搭配

水离子雾化壁炉在会所房间的氛围搭配可以为房间增添舒适、温馨和现代感&#xff0c;以下是一些建议&#xff1a; 主题定位&#xff1a; 根据会所房间的主题和定位选择合适的水离子雾化壁炉款式和设计风格。可以是现代简约、欧式古典或是豪华奢华&#xff0c;确保与房间整体风格…

Java基础学习笔记二

Java基础学习笔记二 6 File1.File类1.1File类概述和构造方法【应用】1.2File类创建功能【应用】1.3File类判断和获取功能【应用】1.4File类删除功能【应用】 2.递归1递归【应用】2递归求阶乘【应用】3递归遍历目录【应用】 3.IO流1 IO流概述和分类【理解】2字节流写数据【应用】…

HL7协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.介绍2.传输协议规范2.1. MLLP2.1.1. 数据头定义2.1.2. 转义字符集 2.2. 规范说明2.3. 消息格式说明 3.HL7结构介绍3.1. 患者建档&#xff08;ADT^A28&#xff09;…

AI应用之智能体介绍

AI应用之智能体介绍 一、LLM介绍二、智能客服应用1&#xff0c;阿里智能能话机器人2&#xff0c;华为对话机器人3&#xff0c;公司基于讯飞知识库和讯飞大模型的智能客服 三、大模型应用平台介绍1&#xff0c;fastgpt2&#xff0c;毕昇3&#xff0c; 字节海外版&#xff08;科学…

学习Nginx(二):版本介绍和安装

版本 Nginx官方定义了Mainline、Stable、Legacy三种版本。 1. Mainline version&#xff08;主线版本&#xff09; 该版本包含最新的功能和bug修复&#xff0c;被视为开发版&#xff0c;即正在活跃开发中的版本。其版本号通常为单数&#xff0c;例如1.25.5。这个版本的更新较快…

Nvidia Jetson编译安装Opencv With CUDA,完善GSTREAMER功能

简介 Nvidia Jetson 官方刷机流程结束以后&#xff0c;虽然安装了opencv&#xff0c;但是此版本是CPU版本&#xff0c;并且不包含Cpp版本。如果想要完整的OpenCV支持&#xff0c;需要从源码编译。本文介绍如何下载编译&#xff0c;并安装OPENCV库&#xff0c;并获得完整的CUDA…

必应bing广告开户费用介绍,必应搜索广告推广开户服务!

微软必应Bing搜索引擎广告成为了企业提升品牌知名度与市场份额的有效途径之一&#xff0c;作为全球第二大搜索引擎&#xff0c;在中国市场正逐步展现出其独特的广告价值与潜力。对于希望拓展在线市场的中国企业而言&#xff0c;通过云衔科技开启必应Bing国内广告推广之旅&#…

谷歌外贸seo优化怎么做?

一般有两种选择&#xff0c;在大型电商平台开展业务&#xff0c;如亚马逊&#xff0c;阿里巴巴等平台&#xff0c;也可以选择搭建自己的独立站 选择在大型电商平台可以方便迅速建立起自己的商铺&#xff0c;不需要考虑太多交易&#xff0c;支付&#xff0c;物流等方面的问题&am…

2024.05.14 Diffusion 代码学习笔记

配环境 我个人用的是Geowizard的环境&#xff1a;https://github.com/fuxiao0719/GeoWizard。 出于方便考虑&#xff0c;用的pytorch官方的docker容器&#xff0c;因此python版本&#xff08;3.10&#xff09;和原作者&#xff08;3.9&#xff09;不同&#xff0c;其余都是一…

Java小游戏之汤姆猫

背景&#xff1a; 博主写过羊了个羊小游戏&#xff0c;客户觉得羊了个羊同学写过了&#xff0c;想换一个&#xff0c;于是笔者想到了汤姆猫。就是那个以前在苹果手机上的猫。 过程&#xff1a; 初始会有一个猫的图片展示&#xff0c;然后你点击按钮&#xff0c;猫会有不同动作…

力扣刷题 day2

快乐数 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09;   图: java // 快乐数 --> 19 > 1^2 9 ^2 82 > 82 > 8 ^ 2 2 ^ 2 ......public boolean isHappy(int n) {// 使用快慢指针int slow n, fast getSum(n);while (slow ! fast) {slow getSum(slo…

【Day3:JAVA运算符、方法的介绍】

目录 1、运算符1.1 赋值运算符1.2 比较运算符1.3 逻辑运算符1.3.1 逻辑运算符概述1.3.2 逻辑运算符分类1.3.3 短路的逻辑运算符 1.4 三元运算符1.5 运算符优先级 2、方法2.1 方法介绍2.2 方法的定义和调用格式2.2.1 方法的调用2.2.2 带参数方法的调用2.2.3 带返回值方法的调用2…

Zookeeper and RPC dubbo

javaguide zookeeper面试题 Zookeeper 啥是Zookeeper干啥的 ZooKeeper 可以被用作注册中心、分布式锁&#xff1b; ZooKeeper 是 Hadoop 生态系统的一员&#xff1b; 构建 ZooKeeper 集群的时候&#xff0c;使用的服务器最好是奇数台。 启动ZK 下载安装解压 不过多赘述 我的…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.7讲 GPIO中断实验-编写按键中断驱动

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

luceda ipkiss教程 66:金属线的钝角转弯

案例分享&#xff1a;金属线的135度转弯&#xff1a; 所有代码如下&#xff1a; from si_fab import all as pdk import ipkiss3.all as i3 from ipkiss.geometry.shape_modifier import __ShapeModifierAutoOpenClosed__ from numpy import sqrtclass ShapeManhattanStub(__…

使用Rufus制作Ubuntu启动盘(windows同理)

问题 想要做系统&#xff0c;首先需要做启动盘&#xff0c;使用Rufus做启动盘操作简单。 解决 1.下载Rufus 这个软件免费的一搜便是&#xff0c;这里下载&#xff1a;Rufus - 轻松创建 USB 启动盘。下载完成后即点即用1无需安装。 打开 2.下载Ubuntu镜像 下载地址&#xff…

Flowable配置多数据源以及指定schema

异常反馈 如有问题可通过微信公众号“假装正经的程序员”反馈 为什么要多源 在项目的实际开发过程中通常会有两种常见的使用Flowable的方式&#xff0c;一种是以独立的服务提供工作流的能力&#xff0c;另一种是以Jar包的形式进行内部集成。 这两种方式各有利弊&#xff0c;…

暴力数据结构之二叉树(堆的相关知识)

1. 堆的基本了解 堆&#xff08;heap&#xff09;是计算机科学中一种特殊的数据结构&#xff0c;通常被视为一个完全二叉树&#xff0c;并且可以用数组来存储。堆的主要应用是在一组变化频繁&#xff08;增删查改的频率较高&#xff09;的数据集中查找最值。堆分为大根堆和小根…

购买商用ssl证书并在windows服务器IIS上配置https域名(案例为阿里云)

阿里云、华为云等各路云都有ssl证书购买&#xff0c;价格相差不大&#xff0c;操作也都差不多&#xff0c;请自行选择。 本文以阿里云操作为案例。 购买SSL证书 点击购买 付款买入 注意&#xff0c;如果自己搞起来有问题&#xff0c;阿里购买的时候建议选择申请协助服务。购买…