【Java八股面试系列】JVM-类和对象加载过程

目录

类和对象的加载过程

类的生命周期

类的加载过程

加载

验证

准备

解析

初始化

类卸载

对象的加载过程


类和对象的加载过程

什么是类加载和对象加载?

  1. 类加载(Class Loading):这是指JVM在运行时将类的字节码文件加载到内存中的过程。类加载的主要任务是找到类的字节码文件,然后读取它并存储在方法区中。这个过程是由类加载器完成的。

  2. 对象加载(Object Loading):这是对象在堆内存中分配空间的过程。当我们在代码中创建一个类的实例时,JVM会在堆内存中为这个对象分配空间,并将其实例化。这个过程是在类加载之后发生的。

简单来说,类加载是将类的字节码文件加载到内存中(Jvm虚拟机的方法区中),而对象加载是为这个类的实例在堆内存中分配空间并初始化。

类的生命周期

类从被加载到虚拟机内存中开始到卸载出内存为止,它的整个生命周期可以简单概括为 7 个阶段::加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)。其中,验证、准备和解析这三个阶段可以统称为连接(Linking)。

这 7 个阶段的顺序如下图所示:

一个类的完整生命周期

类的加载过程

Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚拟机是如何加载这些 Class 文件呢?

系统加载 Class 类型的文件主要三步:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析

加载

主要目的就是使用二进制字节流将class文件加载进Jvm的方法区

类加载过程的第一步,主要完成下面 3 件事情:

  1. 通过全类名获取定义此类的二进制字节流。

  2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构。

  3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口。

加载这一步主要是通过我们后面要讲到的 类加载器 完成的。类加载器有很多种,当我们想要加载一个类的时候,具体是哪个类加载器加载由 双亲委派模型 决定(不过,我们也能打破由双亲委派模型)。

验证

验证是连接阶段的第一步,这一阶段的目的是确保 Class 文件的字节流中包含的信息符合《Java 虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

验证的阶段因为比较关键,保证了后面的运行安全。这个阶段是比较耗费资源的,但是这个验证也是可以自己手动进行关闭的。如果我们的代码都是自己编写,并且引用的代码依赖都是自己使用过多次的,在生产环境的实施阶段就可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

验证阶段主要由四个检验阶段组成:

  1. 文件格式验证(Class 文件格式检查):基于二进制字节流进行实现,确保数据能够安全的加载到方法区之内。

  2. 元数据验证(字节码语义检查)

  3. 字节码验证(程序语义检查)

  4. 符号引用验证(类的正确性检查)

准备

准备阶段是正式为类变量(静态变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:

  1. 这时候进行初始化的都只是类变量,而不是实例变量。实例变量在对象进行初始化的时候都会被分配在堆中

  2. HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到堆中,这个时候类变量则会随着 Class 对象一起存放在 Java 堆中。

  3. 这个阶段设置的初始值只是每个类型的默认值,比如 static int a = 11;这个时候初始化了的a的值为0,而不是11。但是如果是final关键字修饰的变量,则直接会被赋值为设置的值。

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符 7 类符号引用进行。

  • 虚拟机在类加载的解析阶段,会遍历类的常量池,查找所有的符号引用。

  • 对于每一个符号引用,虚拟机会尝试找到它引用的目标类、方法或字段。这可能需要加载其他的类或接口。

  • 如果找到了目标,虚拟机就会将这个符号引用替换为一个直接引用,这个直接引用可以直接访问目标类、方法或字段。

  • 如果找不到目标,或者目标不是一个有效的类、方法或字段(例如,尝试访问一个不存在的类或方法),那么解析过程就会失败,并且会抛出一个异常。

初始化

初始化阶段是执行初始化方法 <clinit> ()方法的过程,是类加载的最后一步,这一步 JVM 才开始真正执行类中定义的 Java 程序代码(字节码)。

说明:<clinit> ()方法是编译之后自动生成的。

对于初始化阶段,虚拟机严格规范了有且只有 6 种情况下,必须对类进行初始化(只有主动去使用类才会初始化类):

  1. 当遇到 new、 getstatic、putstatic 或 invokestatic 这 4 条字节码指令时,比如 new 一个类,读取一个静态字段(未被 final 修饰)、或调用一个类的静态方法时。

    • 当 jvm 执行 new 指令时会初始化类。即当程序创建一个类的实例对象。

    • 当 jvm 执行 getstatic 指令时会初始化类。即程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。

    • 当 jvm 执行 putstatic 指令时会初始化类。即程序给类的静态变量赋值。

    • 当 jvm 执行 invokestatic 指令时会初始化类。即程序调用类的静态方法。

  2. 使用 java.lang.reflect 包的方法对类进行反射调用时如 Class.forname("..."), newInstance() 等等。如果类没初始化,需要触发其初始化。

  3. 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化。

  4. 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。

  5. MethodHandleVarHandle 可以看作是轻量级的反射调用机制,而要想使用这 2 个调用 就必须先使用 findStaticVarHandle 来初始化要调用的类。

类卸载

卸载类即该类的 Class 对象被 GC。

卸载类需要满足 3 个要求:

  1. 该类的所有的实例对象都已被 GC,也就是说堆不存在该类的实例对象。

  2. 该类没有在其他任何地方被引用

  3. 该类的类加载器的实例已被 GC

所以,在 JVM 生命周期内,由 jvm 自带的类加载器加载的类是不会被卸载的。但是由我们自定义的类加载器加载的类是可能被卸载的。

只要想通一点就好了,JDK 自带的 BootstrapClassLoader, ExtClassLoader, AppClassLoader 负责加载 JDK 提供的类,所以它们(类加载器的实例)肯定不会被回收。而我们自定义的类加载器的实例是可以被回收的,所以使用我们自定义加载器加载的类是可以被卸载掉的。

对象的加载过程

Java 对象的创建过程——五步

  1. 检查类是否已经被加载

    new关键字时创建对象时,首先会去运行时常量池中查找该引用所指向的类有没有被虚拟机加载,如果没有被加载,那么会进行类的加载过程。(加载将class文件读取到内存中,使用加载器进行加载)

  2. 为对象分配内存空间

    当类加载检查通过后,虚拟机会为新生对象分配内存空间,对象所需内存空间的大小在类加载完成后就已经确定了。为新生对象分配内存空间其实就是在Java堆中划分出一块确定大小的内存分配给新生对象。分配内存的方式有“指针碰撞”和“空闲列表”两种,选择哪种分配方式取决于Java堆内存是否规整。

    内存分配的两种方式

    • 指针碰撞 使用场合:堆内存规整(即没有内存碎片)的情况下。 实现原理:将用过的内存都整合到一边,没有用过的内存放到另一边,中间有一个分界指针,当需要为新对象分配内存空间时,只需要将分界指针向没有用过的内存一侧移动对象内存大小位置即可。

    • 空闲列表 使用场合:堆内存不规整的情况下。(JDK8默认的GR垃圾回收方式,是不规整的方式) 实现原理:虚拟机会维护一个列表,该列表记录了哪些内存是可用的,当需要为新对象分配内存空间时,只需要在列表中找一块足够大小的内存分配给对象实例,然后更新列表记录。 选择以上两种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器垃圾采用的垃圾收集算法

  3. 对象初始化零值

    内存分配完成后,虚拟机需要将新分配的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段可以在Java代码中可以不赋初始值就直接使用,程序能够访问这些实例字段的数据类型所对应的零值。

  4. 设置对象头

    初始化零值之后,虚拟机需要对对象头进行必要的设置,例如这个对象是哪个类的实例,如何才能找到这个类的元数据信息,对象的哈希码、GC 分代年龄、锁标志位、偏向锁标志位、线程持有的锁信息、对象是否可用等信息会存放到对象头中。另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

  5. 执行init方法

    执行完new指令后会接着执行init方法,将对象按照程序员的需求来进行初始化,这样一个真正可用的对象才算完全产生出来。

上述为无父类的对象创建过程。对于有父类的对象创建过程,还需满足如下条件:

  1. 先加载父类;再加载本类;

  2. 先执行父类的实例的初始化方法init(成员变量、构造代码块),父类的构造方法;执行本类的实例的初始化方法init(成员变量、构造代码块),本类的构造方法。

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

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

相关文章

Cubase学习:音频转midi

大家好!我是诗书画唱!今天要分享的小技巧就是Cubase中的音频转midi的功能!希望对你有所帮助!以后我会在这个账号分享自己知道的很多小技巧!关注我!不迷路!大家也可以关注我后,在我的空间搜索关键词,找到各种对应的教程进行学习,非常的方便!而且自己的教程会尽可能纠…

算法学习——LeetCode力扣二叉树篇3

算法学习——LeetCode力扣二叉树篇3 116. 填充每个节点的下一个右侧节点指针 116. 填充每个节点的下一个右侧节点指针 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树…

【Linux】学习-深入了解文件的读与写

深入了解语言级别(C语言)文件操作的"读"与"写" 在学习前&#xff0c;我们先要知道在Linux下的一个原则&#xff1a;一切皆是文件 如何理解呢&#xff1f;举个外设的例子&#xff0c;比如键盘和显示器&#xff0c;这两个外设也可以其实本质上也是文件&…

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-Viterbi译码原理

目录 一、引言 二、Viterbi译码的基本原理 2.1 卷积码与网格图 2.2 Viterbi算法的核心思想 2.3 路径度量与状态转移 三、Viterbi译码算法工作原理详解 3.1 算法流程 3.2 关键步骤 3.3 译码算法举例 3.4 性能特点 四、Viterbi译码的应用场景 4.1 移动通信系统 4.2 卫…

人工智能如何彻底改变身份欺诈

据 AuthenticID 称&#xff0c;近一半的企业报告合成身份欺诈有所增加&#xff0c;而生物识别欺骗和伪造 ID 欺诈尝试也有所增加。 在当今的数字化存在中&#xff0c;消费者和企业都面临着新的挑战&#xff0c;从考虑数字身份的影响到应对生成人工智能等新工具的使用和流行。与…

力扣[面试题 01.02. 判定是否互为字符重排(哈希表,位图)

Problem: 面试题 01.02. 判定是否互为字符重排 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a;哈希表 1.若两个字符串长度不相等&#xff0c;则一定不符合题意&#xff1b; 2.创建一个map集合&#xff0c;先将字符串s1中的每一个字符与其对应的数量存入集合…

计算机算术

计算机算术 数据是什么 数据是各种各样的信息&#xff0c;如数字、文本、计算机程序、音乐、图像、符号等等&#xff0c;实际上&#xff0c;信息可以是能够被计算机存储和处理的任何事物。 位与字节 计算机中存储和处理信息的最小单位是位&#xff08;Binary digit比特&#x…

CVE-2022-0760 漏洞复现

CVE-2022-0760 NSS [HNCTF 2022 WEEK2]ohmywordpress 【CVE-2022-0760】 题目描述&#xff1a;flag在数据库里面。 开题&#xff1a; 顺着按钮一直点下去会发现出现一个按钮叫安装WordPress 安装完之后的界面&#xff0c;有一个搜索框。 F12看看network。 又出现了这个Wor…

计算机二级C语言备考学习记录

一、C语言程序的结构 1.程序的构成&#xff0c;main函数和其他函数。 程序是由main函数和其他函数构成main作为主函数&#xff0c;一个C程序里只有一个main函数其他函数可以分为系统函数和用户函数&#xff0c;系统函数为编译系统提供&#xff0c;用户函数由用户自行编写 2.…

亚马逊认证考试系列 - 知识点 - LightSail介绍

一、引言 在当今云计算的时代&#xff0c;亚马逊网络服务&#xff08;AWS&#xff09;已成为业界领先的云服务提供商。其中&#xff0c;LightSail服务是AWS为简化云计算的入门和使用而推出的一项服务。它特别适合那些想要快速搭建网站、开发环境或小型应用的用户。通过LightSa…

提升MySQL访问性能

1. 读写分离 设置多个从数据库&#xff0c;从数据库可能在多个机器中。写操作在主数据库进行主数据库提供数据的主要依据 缓解了MySQL的读压力。 主从复制原理图如下 如果对于读操作有一致性要求&#xff0c;那么读操作去主数据库即可。 2. 连接池 因为一个请求必须要…

【数学建模】【2024年】【第40届】【MCM/ICM】【C题 网球运动中的“动量”】【解题思路】

一、题目 &#xff08;一&#xff09; 赛题原文 2024 MCM Problem C: Momentum in Tennis In the 2023 Wimbledon Gentlemen’s final, 20-year-old Spanish rising star Carlos Alcaraz defeated 36-year-old Novak Djokovic. The loss was Djokovic’s first at Wimbledon…

qt-C++笔记之判断一个QLabel上有没有load图片

qt-C笔记之判断一个QLabel上有没有load图片 code review! 在Qt框架中&#xff0c;QLabel是用来显示文本或者图片的一个控件。如果你想判断一个QLabel控件上是否加载了图片&#xff0c;你可以检查它的pixmap属性。pixmap属性会返回一个QPixmap对象&#xff0c;如果没有图片被加…

2024.2.10 DMS(数据库管理系统)初体验

数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件&#xff0c;用于建立、使用和维护数据库&#xff0c;简称DBMS。它对数据库进行统一的管理和控制&#xff0c;以保证数据库的安全性和完整性。用户通过DBMS访问数据库中的数据&#xff0c;数据库管…

【笔记】Harmony学习:下载安装 DevEco Studio 开发工具IDE

IDE 安装 从官网下载DevEco Studio 安装包后进行安装&#xff0c; 安装完毕后&#xff0c;本地环境可能要配置相关工具&#xff0c;可以通过下面的诊断检测一下本地环境&#xff0c;通过蓝色“Set it up now” 可以快速安装。 1. Node.js (for ohpm) 2. ohpm 下载op的包管理&a…

【Chrono Engine学习总结】3-地型terrain

由于Chrono的官方教程在一些细节方面解释的并不清楚&#xff0c;自己做了一些尝试&#xff0c;做学习总结。 1、关于物体材质 在介绍地型之前&#xff0c;要初步了解chrono中关于材质的一些基本概念。 首先&#xff0c;最基本的材质类是ChMaterialSurface,其进一步包括&…

LeetCode---383周赛

题目列表 3028. 边界上的蚂蚁 3029. 将单词恢复初始状态所需的最短时间 I 3030. 找出网格的区域平均强度 3031. 将单词恢复初始状态所需的最短时间 II 一、边界上的蚂蚁 这题没什么好说的&#xff0c;模拟就行&#xff0c;本质就是看前缀和有几个为0。 代码如下 class S…

MySQL篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、SQL 语言包括哪几部分?每部分都有哪些操作关键二、完整性约束包括哪些?三、什么是锁?四、什么叫视图?游标是什么?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,…

【大厂AI课学习笔记】【1.6 人工智能基础知识】(1)人工智能、机器学习、深度学习之间的关系

6.1 人工智能、机器学习与深度学习的关系 必须要掌握的内容&#xff1a; 如上图&#xff1a;人工智能>机器学习>深度学习。 机器学习是人工智能的一个分支&#xff0c;该领域的主要研究对象是人工智能&#xff0c;特别是如何在经验学习中改进具体算法的性能。 深度学习…

MySQL-视图(VIEW)

文章目录 1. 什么是视图&#xff1f;2. 视图 VS 数据表3. 视图的优点4. 视图相关语法4.1 创建视图4.2 查看视图4.3 修改视图4.4 删除视图4.5 检查选项 5. 案例6. 注意事项 1. 什么是视图&#xff1f; MySQL 视图&#xff08; View&#xff09;是一种虚拟存在的表&#xff0c;同…