java 重点知识 — JVM存储模块与类加载器

news2025/3/11 3:08:48

 1 jvm主要模块

方法区

存储了由类加载器从.class文件中解析的类的元数据(类型信息、域信息、方法信息)及运行时常量池(引用符号及字面量)。

所有线程共享;内存不要求连续,可扩展,可能发生垃圾回收(如卸载类)。

存储内容:1)所有new的对象及数组。2)静态变量及字符串常量。

一个jvm实例只有一个堆,所有线程共享,包含了新生代和老生代。

栈区

线程私有。在线程创建时创建,线程销毁时销毁。

记录了局部变量引用、操作数栈等。每调用一个方法生成一个栈帧,后进先出。

PC寄存器

指令计数器,存储指向下一条指令的地址。

本地方法栈

和栈区功能一样,但执行的是本地的方法。

表 jvm的主要模块

1.1 常量池

经过编译后生成的.class文件,包含了元数据(类型信息、域信息及方法信息的原始表示)及类文件常量池(符号引用及字面量)。

而方法区存储的是运行时,当类被加载后解析的元数据及常量池(运行时常量池)。

1.1.1 永久代到元空间的演变

jdk1.8之前方法区也成为永久代。存储于堆中。jdk1.8及之后,被元空间取代。元空间不在jvm的内存中,而在本地内存。

元空间替代永久代,有以下优势:

  1. 内存空间不受jvm的限制,而是由物理内存决定。用户可以配置元空间大小。
  2. 类的元数据在类卸载时由GC回收,效率更高效。

2 类加载器

负责将.class 文件加载到JVM内存,并生成对应的Class<?>对象。职责包括:

  1. 加载字节码:从文件系统、网络或其他来源读取.class文件。
  2. 定义类结构:将字节码转换成JVM内部的类元数据。
  3. 维护类隔离:通过不同类加载器实现类的作用域隔离。

2.1 类加载器层级

启动类加载器

Bootstrap ClassLoader,加载JAVA_HOME\lib 目录下的核心类库。 有JVM自身实现,无法在代码中直接引用。

扩展类加载器

Extension ClassLoader,加载JAVA_HOME\lib\ext目录下的扩展类库。

应用程序类加载器

Application ClassLoader,加载classpath目录下的用户类(项目代码、第三方库)

图 系统自带的类加载器

图 类加载器的层级

2.2 双亲委派模型

类加载器采用了“双亲委派模型”,即加载类时,先委托给父类加载器加载,如果加载不到,则由自己加载。这里的父类,并不是指具有继承关系,而是通过合成复用,来设置父类加载器。

要求,除顶层的启动类加载器外,其他的加载器都应有自己的父加载器。

在实现自定义类加载器时,需要继承抽象类ClassLoader,其伪代码如下:

public abstract class ClassLoader {

    private final ClassLoader parent;

    protected ClassLoader(ClassLoader parent) {
        this.parent = parent;
    }

    public Class<?> loadClass(String name) throws ClassNotFoundException {
        // 首先确定这个类是否被加载
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            if (parent != null) {
                c = parent.loadClass(name);
            } else { // 如果父加载器不存在,则将启动类加载器作为父加载器
                c = findBootstrapClass(name);
            }
            if (c == null) {
                c = findClass(name); // 自定义实现加载类
            }
        }
        return c;
    }

    /**
     * 确定这个类是否已加载
     */
    private Class<?> findLoadedClass(String name) {
        return null;
    }

    /**
     * 通过启动类加载器查找
     */
    private native Class<?> findBootstrapClass(String name);

    /**
     * 自定义实现加载类。在实现自定义加载器时,推荐重写这个方法,而不要动loadClass方法
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
}

2.2.1 优缺点

优点:

  1. 保护核心类库安全,防止用户自定义同名类覆盖核心类,避免安全漏洞(如恶意代码注入)。
  2. 保证类的全局唯一性,无论通过哪个类加载器加载,最终得到的都是同一个类。

缺点:

  1. 灵活性受限,例如在模块化开发时,如果不同模块要求加载的类库版本不一致,双亲委派模式难以实现。(Tomcat打破了双亲委派模式)
  2. SPI服务加载矛盾,例如核心接口(如java.sql.Driver)y由启动类加载器加载,但实现类(如Mysql驱动)需要由应用类加载器加载。
  3. 热部署困难,类一旦被加载后,无法通过同一类加载器重新加载修改后的类,需要重启部署整个项目(即所有类需要重新被加载)。

2.3 打破双亲委派模型

Java默认采用双亲委派模型来加载类,但是在某些场景下,我们需要打破这种方式,来实现特定的需求。

2.3.1 SPI服务—java.sql.Driver

SPI(Service Provide Interface),服务供给接口。Java 1.5新添加的一个内置标注。Java核心库提供特定的服务接口,用户或第三方服务来实现这个接口。同时在META-INFA/services文件夹下,编写以该接口全限定名命名的文档,内容为实现类的全限定名。然后Java根据该全限定名来加载这个实现类。

下面以java.sql.Driver 为例,介绍SPI。

java.sql.Driver 接口主要职责是建立数据库连接。

图 mysql-connector-java 中Driver的实现类及服务提供文件

JDK 核心库中的java.sql.DriverManager,负责管理Driver类,包括Driver实现类的加载。其同时支持两种加载驱动类的方式:

1)加载系统属性jdbc.drivers指定的驱动类。

Class.forName(“Driver实现类全限定名”, true, ClassLoader.getSystemClassLoader());

ClassLoader.getSystemClassLoader()方法获取系统类加载器(即默认的应用程序加载器Application ClassLoader)

2)加载SPI机制提供的驱动类。

ServiceLoader.load(Driver.class);

// ServiceLoader

public static <S> ServiceLoader<S> load(Class<S> service) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    return ServiceLoader.load(service, cl);
}

SPI机制用的类加载器是通过Thread.currentThread().getContextClassLoader();获取。该方法获取的类加载器默认为应用程序加载器。

2.3.2 模块化部署—Tomcat容器

假如在Tomcat同时部署两个应用web1和web2。其中web1依赖spring-core-5.3.0.jar。而web2依赖spring-core-6.0.0.jar。Tomcat默认是单JVM运行多个Web应用。如果采用双亲委派策略,假如web1的某个父加载器加载了spring-core-5.3.0.jar,而到web2时,由于该类已被加载,就不会加载spring-core-6.0.0.jar,那么此时,web2 会报异常NoSuchMethodError或版本冲突。

Common

加载Tomcat通用类。

Catalina

加载Tocmat自身类。

Shared

加载所有Web应用共享的类库(可配置)。

WebAppClassLoader

每个Web应用独立的类加载器,优先从自身类路径(WEB-INF/class和WEB-INF/lib)加载。

图 Tomcat的类加载器

图 Tomcat的类加载器层级

WebAppClassLoader打破了双亲委派模型,会优先自己加载,而非直接委托父类加载器。

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

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

相关文章

idea中使用DeepSeek让编程更加便捷

IDEA中使用DeepSeek让编程更加便捷 对于开发者来说&#xff0c;IDEA&#xff08;IntelliJ IDEA&#xff09;是一款强大的开发工具。但你是否知道&#xff0c;通过安装DeepSeek这款插件&#xff0c;可以让你的编程体验更上一层楼&#xff1f;今天&#xff0c;我们就来聊聊如何在…

elasticsearch是哪家的

Elasticsearch&#xff1a;数据搜索与分析的领航者 在当今这个信息爆炸的时代&#xff0c;快速且准确地处理海量数据成为了众多企业和组织追求的目标。而Elasticsearch正是在这个背景下脱颖而出的一款强大的开源搜索引擎。它是由位于美国加利福尼亚州的Elastic公司所开发和维护…

5. MySQL 存储引擎(详解说明)

5. MySQL 存储引擎(详解说明) 文章目录 5. MySQL 存储引擎(详解说明)1. 查看存储引擎2. 设置系统默认的存储引擎3. 设置表的存储引擎3.1 创建表时指定存储引擎3.2 修改表的存储引擎 4. 引擎介绍4.1 InnoDB 引擎&#xff1a;具备外键支持功能的事务存储引擎4.2 MyISAM 引擎&…

基于LabVIEW的伺服阀高频振动测试闭环控制系统

为实现伺服阀在设定位置上下快速移动&#xff08;1kHz控制频率&#xff09;的振动测试目标&#xff0c;需构建基于LabVIEW的闭环控制系统。系统需满足高速数据采集、实时控制算法&#xff08;如PID或自适应控制&#xff09;、高精度电流驱动及传感器反馈处理等需求。结合用户提…

97.在 Vue 3 中使用 OpenLayers 根据两行根数 (TLE) 计算并显示卫星轨迹(EPSG:3857)

前言 在许多卫星应用场景中&#xff0c;我们需要 基于 TLE&#xff08;Two-Line Element Set, 两行根数&#xff09;计算卫星轨迹&#xff0c;并在地图上进行可视化。本文将使用 Vue 3 OpenLayers satellite.js&#xff0c;实现 实时计算卫星轨迹&#xff0c;并在地图上动态更…

fastjson漏洞#不出网#原理#流量特征

原理 本质是java的反序列化漏洞&#xff0c;由于引进了自动检测类型的&#xff08;autotype&#xff09;功能&#xff0c;fastjson在对json字符串反序列化的时候&#xff0c;会读取type内容&#xff0c;会试图将json内容反序列化成这个对象&#xff0c;并调用这个类的setter方…

Linux系统基于ARM平台的LVGL移植

软硬件介绍&#xff1a;Ubuntu 20.04 ARM 和&#xff08;Cortex-A53架构&#xff09;开发板 基本原理 LVGL图形库是支持使用Linux系统的Framebuffer帧缓冲设备实现的&#xff0c;如果想要实现在ARM开发板上运行LVGL图形库&#xff0c;那么就需要把LVGL图形库提供的关于帧缓冲设…

电力场景绝缘子缺陷分割数据集labelme格式1585张4类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1585 标注数量(json文件个数)&#xff1a;1585 标注类别数&#xff1a;4 标注类别名称:["broken part","broken insulat…

【计算机网络】深入解析 HTTP 协议的概念、工作原理和通过 Fiddler 抓包查看 HTTP 请求/响应的协议格式

网络原理— HTTP 1. 什么是HTTP? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议&#xff1a; HTTP 往往是基于传输层的 TCP 协议实现的 (HTTP1.0,HTTP1.1,HTTP2.0 均为TCP,HTTP3基于UDP实现) 我们平时打开一个网站&#xff0c;就是通过HTTP协议来…

SpringBoot优雅关机,监听关机事件,docker配置

Spring Boot 提供了多种方法来实现优雅停机&#xff08;Graceful Shutdown&#xff09;&#xff0c;这意味着在关闭应用程序之前&#xff0c;它会等待当前正在处理的请求完成&#xff0c;并且不再接受新的请求。 一、优雅停机的基本概念 优雅停机的主要步骤如下&#xff1a; …

在【k8s】中部署Jenkins的实践指南

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Jenkins简介 2、k8s简介 3、什么在…

Unity DOTS从入门到精通之 C# Job System

文章目录 前言安装 DOTS 包C# 任务系统Mono 环境DOTS 环境运行作业NativeContainer 前言 作为 DOTS 教程&#xff0c;我们将创建一个旋转立方体的简单程序&#xff0c;并将传统的 Unity 设计转换为 DOTS 设计。 Unity 2022.3.52f1Entities 1.3.10 安装 DOTS 包 要安装 DOTS…

【Godot4.4】浅尝Godot中的MVC

概述 基于一个Unity的视频。学习了一下基本的MVC概念&#xff0c;并尝试在Godot中实现了一下。 原始的MVC&#xff1a; Godot中的MVC&#xff1a; Model、View和Controller各自应该实现的功能如下&#xff1a; Model: 属性(数据字段)数据存取方法数据更新信号 View: 控…

Elasticsearch为索引设置自动时间戳,ES自动时间戳

文章目录 0、思路1、配置 ingest pipeline2、在索引映射中启用_source字段的时间戳3、使用 index template 全局设置时间戳4、写入测试数据5、验证结果6、总结 在使用 Elasticsearch 进行数据存储和检索时&#xff0c;时间戳字段是一个非常重要的组成部分。它可以帮助我们追踪数…

计算机网络:计算机网络的组成和功能

计算机网络的组成&#xff1a; 计算机网络的工作方式&#xff1a; 计算机网络的逻辑功能; 总结&#xff1a; 计算机网络的功能&#xff1a; 1.数据通信 2.资源共享 3.分布式处理:计算机网络的分布式处理是指将计算任务分散到网络中的多个节点&#xff08;计算机或设备&…

FPGA设计时序约束用法大全保姆级说明

目录 一、序言 二、时序约束概览 2.1 约束五大类 2.2 约束功能简述 2.3 跨时钟域约束 三、时序约束规范 3.1 时序约束顺序 3.2 约束的优先级 四、约束示例 4.1 设计代码 4.2 时序结果 4.2.1 create_clock 4.2.2 create_generated_clock 4.2.3 Rename_Auto-Derive…

云服务运维智能时代:阿里云操作系统控制台

阿里云操作系统控制台 引言需求介绍操作系统使用实例获得的帮助与提升建议 引言 阿里云操作系统控制台是一款创新型云服务器运维工具&#xff0c;专为简化用户的运维工作而设计。它采用智能化和可视化的方式&#xff0c;让运维变得更加高效、直观。借助AI技术&#xff0c;控制…

硬件学习笔记--48 磁保持继电器相关基础知识介绍

目录 1.磁保持继电器工作原理 2.磁保持继电器内部结构及组成部分 3.磁保持继电器主要参数 4.总结 1.磁保持继电器工作原理 磁保持继电器利用永磁体的磁场和线圈通电产生的磁场相互作用&#xff0c;实现触点的切换。其特点在于线圈断电后&#xff0c;触点状态仍能保持&#…

简记_硬件系统设计之需求分析要点

目录 一、 功能需求 二、 整体性能需求 三、 用户接口需求 四、 功耗需求 五、 成本需求 六、 IP和NEMA防护等级需求 七、 认证需求 功能需求 供电方式及防护 供电方式&#xff1a;市电供电、外置直流稳压电源供电、电池供电、PoE&#xff08;Power Over Ether…

ubuntu 20.04下ZEDmini安装使用

提前安装好显卡驱动和cuda&#xff0c;如果没有安装可以参考我的这两篇文章进行安装&#xff1a; ubuntu20.04配置YOLOV5&#xff08;非虚拟机&#xff09;_ubuntu20.04安装yolov5-CSDN博客 ubuntu20.04安装显卡驱动及问题总结_乌班图里怎么备份显卡驱动-CSDN博客 还需要提前…