JVM- 浅谈Java 类加载过程

基本概念

Java 类加载过程是 Java 虚拟机(JVM)运行 Java 程序时的重要组成部分。这个过程主要包括以下几个阶段:

  1. 加载(Loading):

    • 在这个阶段,JVM 通过类的全限定名来获取此类的二进制字节流。
    • 加载的数据来源可以是 .class 文件、网络、其他文件系统,甚至是动态生成的字节码。
    • 加载后,数据被转换为方法区内的数据结构(比如类型信息、常量池、方法数据等)。
    • 创建一个代表这个类的 java.lang.Class 对象,作为方法区这些数据的访问入口。
  2. 链接(Linking):

    • 验证(Verification):确保被加载的类满足 JVM 规范,没有安全问题。
    • 准备(Preparation):为类变量(静态变量)分配内存,并设置默认初始值,这些变量所使用的内存在方法区中进行分配。
    • 解析(Resolution):将类、接口、字段和方法的符号引用转换为直接引用。
  3. 初始化(Initialization):

    • 这个阶段是执行类构造器 <clinit>() 方法的过程。
    • <clinit>() 方法由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并而成。
    • 初始化阶段是执行这个类构造器的过程。
  4. 使用(Using):

    • 在完成了初始化后,类就可以被使用了,比如创建实例、调用类的静态方法等。
  5. 卸载(Unloading):

    • 当类不再被需要时,它会被卸载。卸载条件通常是该类的 Class 对象没有任何引用,且其类加载器的实例也被垃圾回收。
    • 卸载后,该类所占用的资源会被释放。

这个过程是 Java 程序运行的基础,确保了 Java 程序可以在不同的环境下以相同的方式执行,同时也支持了 Java 强大的动态性能。

加载(Loading)阶段

Java 类加载(Loading)阶段是 Java 类加载过程中的第一阶段,其主要任务是将类的二进制数据从不同的数据源转换为方法区内的数据结构,并在堆中创建一个 java.lang.Class 对象来封装这些数据结构。这一阶段的详细过程如下:

1. 类的定位

  • 查找类的二进制数据:类加载器首先需要找到类的二进制表示。这通常涉及到从文件系统中读取 .class 文件,但也可以从其他源如网络、ZIP 文件、运行时生成的数据等地方获取。
  • 类加载器:Java 使用了委托模型来加载类。通常,类加载器会首先请求父类加载器加载类。如果父类加载器无法找到或加载该类,子类加载器才会尝试加载。

2. 类的读取

  • 读取二进制数据:类加载器将从其源中读取类的二进制数据。这些数据包括 Java 类的各种组成部分,如方法、字段和其他关联的元数据。

3. 解析为内部结构

  • 转换为方法区的表示:读取进来的二进制数据被转换成方法区中的内部数据结构。这包括运行时常量池、字段和方法数据。
  • 运行时常量池:它是方法区的一部分,用于存储编译期生成的各种字面量和符号引用,这部分内容将在后续的链接阶段被使用。

4. 创建 java.lang.Class 对象

  • 在堆中创建 Class 对象:JVM 在堆中创建一个 java.lang.Class 对象,代表刚刚加载的类。这个对象作为程序访问方法区内类定义数据的入口,同时也被用于反射操作。
  • 关联引用:这个 Class 对象包含了指向方法区内类定义数据的引用,如对运行时常量池的引用等。

5. 链接到其他类和接口

  • 在类加载过程中,如果发现当前类有引用到其他类或接口(例如继承或实现),那么这些类或接口也将被加载。

6. 安全检查

  • 验证格式:检查加载的类或接口的格式是否符合 JVM 规范。
  • 安全性检查:如果启用了安全管理器,这一阶段还可能涉及安全性检查。

总结

类的加载是一个相对复杂的过程,涉及查找、读取、解析类数据,并在 JVM 内部创建相应的表示。这个过程是整个类生命周期中最初的阶段,为后续的链接、初始化等阶段奠定基础。由于 JVM 规范对类加载器的实现没有严格限制,因此不同的 JVM 实现或不同的类加载器可能在具体实现上有所差异。

链接(Linking)阶段

Java 类加载过程中的链接(Linking)阶段紧随类的加载(Loading)阶段,主要负责将已加载的类或接口的二进制数据合并到 Java 虚拟机的运行时状态中。链接阶段包括三个子阶段:验证(Verification)、准备(Preparation)和解析(Resolution)。这些阶段确保了加载的类在逻辑上正确,且与 JVM 的内存结构兼容。

1. 验证(Verification)

验证是确保加载的类或接口遵循 Java 虚拟机规范,并且不会对 JVM 的安全造成威胁的过程。

  • 文件格式验证:检查加载的类或接口是否具有正确的内部结构(例如正确的魔数、版本号)。
  • 元数据验证:检查类或接口的元数据是否符合 Java 语言规范,如数据类型、方法签名。
  • 字节码验证:进行更深入的检查,确保代码遵循逻辑约束,比如控制流、变量初始化、方法调用等的正确性。
  • 符号引用验证:确保符号引用指向正确的对象。

2. 准备(Preparation)

准备阶段负责为类中的静态变量分配内存,并设置类变量的初始默认值。

  • 内存分配:在方法区中为类变量(也称为静态字段)分配内存。这不包括实例变量,实例变量会在对象实例化时随对象一起分配在堆中。
  • 默认初始化:静态变量在准备阶段会被初始化为默认值,例如 int 类型的默认值为 0,引用类型的默认值为 null。这些默认值通常不等同于在 Java 代码中指定的值。

3. 解析(Resolution)

解析阶段是将类、接口、字段和方法的符号引用转换为直接引用的过程。

  • 符号引用:这是一种抽象的引用,用类的全限定名、字段的名称和描述符等表示。
  • 直接引用:这是一种具体的引用,直接指向目标的内存地址或者是能间接定位到目标的指针。直接引用在类型解析后生成。
  • 解析动作:包括类和接口的解析、字段解析、类方法解析、接口方法解析等。这个过程可能涉及到加载其他未被加载的类。

总结

链接阶段是类加载过程的重要组成部分,它确保了类或接口被正确地整合到 JVM 的内部结构中。通过验证、准备和解析这三个子阶段,JVM 确保了代码的安全性和稳定性,同时为后续的初始化阶段做好准备。这个过程对于保持 Java 应用的健壮性和跨平台功能至关重要。不同的 JVM 实现可能在细节上有所差异,但大体流程是一致的。

初始化(Initialization)阶段

Java 类的初始化(Initialization)阶段是类加载过程的一个重要环节。在此阶段,Java 虚拟机(JVM)负责执行类构造器 <clinit>() 方法,该方法由编译器自动合成,用于初始化类变量和执行静态代码块。以下是初始化阶段的详细介绍:

1. 触发条件

类的初始化阶段会在满足以下任一条件时触发:

  • 当创建一个类的实例时(例如,使用 new 关键字)。
  • 当访问一个类的静态方法或静态字段时(除了使用 finalstatic 定义的常量字段,因为它们在编译时就已被解析)。
  • 当使用 java.lang.reflect 包的方法对类进行反射调用时。
  • 当初始化一个类的派生类时(首先需要初始化其父类)。
  • 当虚拟机启动时,用户指定的主类(包含 main() 方法的类)被初始化。

2. <clinit>() 方法

  • 合成过程:编译器自动收集类中的所有静态变量赋值动作和静态语句块(static {} 块),按照这些语句在源文件中的顺序合成 <clinit>() 方法。
  • 执行:该方法不需要显式调用,由 JVM 在类初始化时自动执行。

3. 初始化过程

  • 单线程:初始化一个类包括执行该类的 <clinit>() 方法。JVM 保证这个方法在多线程环境中被安全地执行,即同一类的 <clinit>() 方法在多个线程中只会被执行一次。
  • 父类初始化:如果一个类有父类,JVM 会先初始化其父类,除非父类已经被初始化。
  • 执行顺序:静态变量的赋值和静态代码块的执行顺序严格遵循它们在类中定义的顺序。

4. 特殊情况

  • 接口初始化:当一个接口中定义了静态字段(final 且 static),且这个字段被用到时,会触发该接口的初始化。
  • 未被使用的类:如果一个类没有被使用,那么它可能永远不会被初始化。

5. 错误处理

  • 异常:如果在初始化过程中发生了异常,并且没有被捕获,那么后续尝试初始化这个类的行为将会被 JVM 标记为错误,并抛出 java.lang.NoClassDefFoundError 或类似的错误。

总结

初始化阶段是类加载过程的关键部分,负责执行类构造器 <clinit>() 方法,以初始化类变量和执行静态代码块。JVM 通过精确控制和同步,确保类在多线程环境下安全地进行初始化。初始化阶段是类生命周期中非常重要的一环,它为类的后续使用做好了准备。

使用(Using)和卸载(Unloading)

在 Java 类加载的生命周期中,使用(Using)和卸载(Unloading)是最后两个阶段。它们标志着类在 Java 虚拟机(JVM)中的活跃使用和最终的回收。

使用(Using)

在类被加载、链接、初始化之后,它就处于可使用状态。这个阶段,类的功能可以被完全利用,具体包括:

  1. 创建实例:可以通过 new 关键字创建类的实例。
  2. 访问静态成员:可以访问类的静态方法和静态字段。
  3. 反射操作:可以通过反射机制查询类信息、访问成员、调用方法等。
  4. 实现接口:如果类实现了某个接口,可以通过这个接口引用它的实例。
  5. 继承:可以被其他类继承,除非它是一个 final 类。

这个阶段中,类是完全活跃的,可以被应用程序自由使用。

卸载(Unloading)

卸载是类生命周期的最终阶段。在这个阶段,类由 JVM 从内存中移除。类的卸载发生在以下情况:

  1. 类加载器的实例被回收:如果一个类的类加载器的实例被垃圾回收器回收,那么由该类加载器加载的所有类也会被卸载。
  2. 类的实例和 Class 对象无引用:如果一个类没有任何活跃的实例,且其 java.lang.Class 对象也没有在任何地方被引用,那么 JVM 可以选择卸载这个类。
  3. 卸载的条件:Java 规范并没有强制要求 JVM 必须卸载类,也没有规定具体的卸载时间点。因此,不同的 JVM 实现可能有不同的卸载策略。

卸载后,类的二进制数据和在方法区中的所有结构都会被回收,释放出相应的内存空间。

注意点

  • 类卸载的稀有性:在许多 Java 应用程序和运行时环境中,类的卸载不是一件常见的事情。尤其是对于使用系统类加载器或扩展类加载器加载的类,它们通常会伴随 JVM 的整个生命周期。
  • 持久代和元空间:在早期版本的 JVM 中,类的元数据存储在持久代(PermGen)。在 Java 8 及以后的版本中,持久代被元空间(Metaspace)所替代,元空间的大小可以动态调整,减少了类卸载的需求。

总结来说,使用阶段是类在 JVM 中的活跃期,此时类的各项功能都可被利用。卸载阶段是类生命周期的终结,此时类及其相关资源被回收,但在实际应用中类的卸载并不频繁。这两个阶段标志着类在 JVM 中的生命周期的完整性。

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

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

相关文章

C#中的async/await异步编程模型

前言 当谈到异步编程时&#xff0c;C#中的async/await是一个强大且方便的工具。它使得编写并发和异步操作变得更加简单和可读&#xff0c;同时提供良好的可维护性。本文将详细解释async/await的使用&#xff0c;以及如何在C#中有效地利用它来实现异步操作。 目录 前言1. async…

在线教育机构如何借助小程序技术创新

随着人工智能AI技术的发展&#xff0c;我们的生活学习工作方式都在经历变化。在线教育也处于这场变化的核心之中&#xff0c;同样借助这股东风引来了行业的一波红利期。 在正式分享在线教育行业的开始&#xff0c;我们先简单搞清楚什么是在线教育。 在线教育行业是指通过互联…

PCF8591多通道数据读取异常问题

问题描述 PCF8591在循环读取两个通道时&#xff0c;两个通道数据出现交错问题。 例如我们想实现&#xff1a;第一次读取通道一、第二次读取通道二、第三次读取通道一、第四次读取通道二……依次循环 但实际数据&#xff1a;第一次读取的值为0x80、第二次读取的值为通道一的值、…

2023.11.28-电商平台建设03 - 大数据调优手段

1.优化手段 1.1分桶表 HIVE的分桶本质上就是MR的分区操作 建表语句: create table 表名(字段 类型,.... ) clustered by(分桶字段) [sorted by (字段 [asc | desc])] into N buckets --- 定义分桶表核心语句 row format...... 分桶的作用 1) 进行数据采样工作 1.1) …

final关键字-Java

final关键字 一、使用场景1、当不希望类被继承时&#xff0c;可以用final修饰。2、当不希望父类的某个方法被子类覆盖/重写(override)时&#xff0c;可以用final修饰。3、当不希望类的的某个属性的值被修改&#xff0c;可以用final修饰。4、当不希望某个局部变量被修改&#xf…

智能优化算法应用:基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于花授粉算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.花授粉算法4.实验参数设定5.算法结果6.参考文献7.…

Vue实战:图片上传组件开发

图片上传是Web开发中常见的需求之一。下面我们介绍如何使用Vue框架开发一个简单的图片上传组件。 一、需求分析 我们的图片上传组件应具备如下功能&#xff1a; 用户能够选择一张图片进行上传&#xff1b;点击上传按钮后&#xff0c;将选中的图片上传到服务器&#xff1b;显示…

好用的json处理工具He3 JSON

官网地址&#xff1a;https://he3app.com/zh/ json格式化 https://portal.he3app.com/home/extension/json-to-pretty 其他 https://portal.he3app.com/home/category

芯能科技-603105 三季报分析(20231123)

芯能科技-603105 基本情况 公司名称&#xff1a;浙江芯能光伏科技股份有限公司 A股简称&#xff1a;芯能科技 成立日期&#xff1a;2008-07-09 上市日期&#xff1a;2018-07-09 所属行业&#xff1a;电气机械和器材制造业 周期性&#xff1a;1 主营业务&#xff1a;分布式光伏解…

每日一练:简易计算器

1. 题目 设计实现一个简易的计算器&#xff0c;可以进行加减乘除的计算。可以考虑通过GUI和命令行输入等方式实现。 2. 设计思路 创建一个简单的用户界面&#xff0c;可以使用 Python 的 Tkinter模块。在界面上放置按钮&#xff0c;每个按钮代表一个数字、运算符或其他功能。…

家政预约服务管理系统,轻松搭建专属家政小程序

家政预约服务管理系统&#xff0c;轻松搭建专属家政小程序app&#xff1b; 家政服务app开发架构包括&#xff1a; 1. 后台管理端&#xff1a;全面管理家政服务、门店、员工、阿姨信息、订单及优惠促销等数据&#xff0c;并进行统计分析。 2. 门店端&#xff1a;助力各门店及员工…

Linux命令中的符号

目录 1 管道符 | 1.1 | grep [要检索的东西] 1.2 echo | tee 2 重定向 2.1 输出重定向覆盖 > 2.2 输出重定向添加 >> 2.3 文件输入重定向 < 2.4 多行文本输入重定向 << 2.5 常用搭配 2.5.1 终端不显示 > /dev/null 1 管道符 | 我们…

简单递归题

本来不想用递归做的&#xff0c;最后还是用了 题目如下&#xff1a; 洪尼玛有 n 块长度不同的木板&#xff0c;他想用这些木板拼成一个等边三角形的围栏&#xff0c;好将他的草泥马养在这个围栏里面。现在&#xff0c;给你这 n 块木板的长度&#xff0c;洪尼玛想知道他能否拼…

使用.NET8中的.http文件和终结点资源管理器

本文将以.NET8的模板增加的.http文件为引&#xff0c;介绍 Visual Studio 2022 中的 .http 文件编辑器&#xff0c;这是一个用于测试 ASP.NET Core 项目的强大工具。 文章目录 1. 背景2. HTTP 文件介绍2.1 简介2.2 .http 文件语法3. 在 Visual Studio 中使用3.1 终结点资源管理…

基于Spring原生框架构建原生Spring的第一个程序!

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

04_Flutter自定义Slider滑块

04_Flutter自定义Slider滑块 一.Slider控件基本用法 Column(mainAxisAlignment: MainAxisAlignment.start,children: <Widget>[Text("sliderValue: ${_sliderValue.toInt()}"),Slider(value: _sliderValue,min: 0,max: 100,divisions: 10,thumbColor: Colors.…

在线yml和properties相互转换

目前搜索到的大部分代码都存在复杂结构解析丢失问题&#xff0c;所以自己写了一个&#xff0c;经过不充分测试&#xff0c;基本满足使用。 在线地址 除了yml和properties互转之外&#xff0c;还可以生成代码、sql转json等&#xff0c;可以去用一下&#xff0c;用爱发电&#x…

Nacos2.x配置中心源码分析

概述 源码注释参考 git 仓库&#xff0c;对应流程图后续补充&#xff1b; 启动 nacos nacos 启动类&#xff1a; // com.alibaba.nacos.NacosSpringBootApplication(scanBasePackages "com.alibaba.nacos") ServletComponentScan EnableScheduling public class…

查看正在运行的 Docker 服务命令

1.查看包括已停止的容器在内的所有容器 docker ps -a2.查看正在运行的 Docker 服务 docker service ls3.要卸载&#xff08;删除&#xff09;Docker 中的一个容器 bash以服务ztnci为例 docker rm 0939688452dc # 使用容器的 ID 替换这里的 ID如果你知道容器的名称&#xff…

MySQL事务(简单明了)

目录 1. 事务的特性&#xff08;ACID&#xff09;&#xff1a; 2. 事务的语法&#xff1a; 3. 隔离级别&#xff1a; 4. 保存点&#xff08;Savepoints&#xff09;&#xff1a; 5. 示例&#xff1a; 1. 事务的特性&#xff08;ACID&#xff09;&#xff1a; 原子性&#…