JVM(面试用)

news2024/12/23 3:32:17

目录

一、JVM运行时数据区

二、JVM类加载

类加载过程

1、加载(loading)

2、验证(Verification)

3、准备(Perparation)

4、解析(Resolution)

5、初始化(Initialization)

双亲委派模型 

机制

优点

1、避免重复加载类

2、安全性

打破双亲委任模型

三、JVM中的垃圾回收机制

1、死亡对象的判断算法

1)引用计数算法

2)可达性分析算法

2、垃圾回收算法

1)标记-清除法

2)复制算法

3)标记-整理法

4)分代算法


JVM,Java Virtual Machine,Java虚拟机

虚拟机是指软件模拟的具有完整功能的、运行在一个完全隔离的环境中的完整计算机系统

常见的虚拟机:JVM、VMwave、Virtual Box

JVM和其他两个虚拟机的区别:

  1. VMware与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器
  2. JVM则是通过软件模拟Java字节码的指令集,JVM中则是主要保留了PC寄存器,其他的寄存器都进行了裁剪

JVM是一台被定制过的现实当中不存在的计算机

一个运行起来的Java进程就是一个JVM虚拟机,就需要从操作系统申请一大块内存

就会把这个内存划分成不同的区域,每个区域都有不同的作用

一、JVM运行时数据区

Java虚拟机运行时数据区是Java程序在运行过程中使用的内存区域,用于存储程序运行时所需要的数据

这些数据区包括了不同用途的内存区域,每个区域都有特定的作用和生命周期

注意它和Java内存模型(Java Memory Model,JMM)完全不同,属于完全不同的概念

其中堆和方法区都是线程共享的,Java虚拟机栈、本地方法栈、程序计数器是线程私有的

有自己的空间:别的线程也能访问;有自己私有的空间:别的线程无法访问

1、 堆(占据空间最大):存放程序中创建的对象

堆区分为两个区域:新生代和老生代,新生代放新建的对象,当经过一定GC次数之后还存活的对象会放入老生代

垃圾回收时会将Endn中存活的对象放到一个未使用的Survivor中,并把当前的Endn和正在使用的Survivor清除掉

2、Java虚拟机栈:存放方法之间的调用关系,描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息

Java虚拟机栈的生命周期和线程相同

  • 局部变量表:存放编译器可知的8大基本数据类型对象引用存放方法参数和局部变量
  • 操作栈:每个方法会生成一个先进后出的操作栈
  • 动态链接:每个方法会生成一个先进后出的操作栈
  • 方法返回地址:PC寄存器的地址

3、本地方法栈

本地方法栈和虚拟机栈类似,只不过Java虚拟机栈是给JVM使用的,而本地方法栈是给本地方法使用的(使用非Java语言编写的方法,如C、C++)

两种栈都是存放方法之间的调用关系

4、程序计数器:存放下一条要执行的指令的地址

5、方法区(元数据区):存储被虚拟机加载的信息、常量、静态变量、即时编译器编译后的代码等数据的(.class文件加载到内存之后就成了类对象,所以就是存放类对象)

运行常量池是方法区的一部分,存放字面量和字符引用

  • 字面量:字符串(JDK8移动到堆中)、final常量、基本数据类型的值
  • 符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符
class Test{
    public int r=100;//成员变量r处于堆上
    public static int a=10;//静态变量(类属性)包含在类对象中,处在方法区(元数据区)
    
    void main(){
        Test t=new Test();//t是一个引用类型的局部变量,存放在栈的局部变量表中,存储一个对象的地址
                          //new出来的对象在堆上
    }
}

二、JVM类加载

类加载过程

其中前五步是固定的顺序并且也是类加载的过程,其中中间的3步我们都属于连接,所以对于类加载来说总共分为一下几个步骤:加载、连接(验证、准备、解析)、初始化

1、加载(loading)

找到.class文件,打开文件,读取内容。将类的字节码数据从磁盘加载到内存中。这个过程是由类加载器完成的。在加载阶段,虚拟机需要完成一下三件事情:

  • 通过类的全限定名获取类的二进制字节流
  • 将字节流代表的静态存储结构转化为方法区的运行时数据结构
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
2、验证(Verification)

确保类的字节码文件符合虚拟机规范,不会危害虚拟机的运行时环境

主要包括四种验证:文件格式验证、元数据验证、字节码验证、符号引用验证

3、准备(Perparation)

为类的静态变量分配内存并设置初始值(零值)

这里不包括final修饰的static变量,因为final在编译时就分配了初始值

4、解析(Resolution)

将常量池中的符号引用替换为直接引用的过程(初始化常量)

主要包括:类或接口的解析、字段解析、类方法解析、接口方法解析

5、初始化(Initialization)

Java虚拟机真正开始执行类中编写的Java程序代码,将主导权移交给应用程序

初始化阶段就是执行类构造器<clinit>()方法的过程,在初始化阶段,虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步,确保类的初始化只会进行一次

针对类对象进行初始化:设置好类对象中需要的各个属性、static成员变量、静态代码块、以及还可能加载一下父类

双亲委派模型 

双亲委派模型是和Java中多个类加载器(启动类加载器、扩展类加载器、应用程序类加载器)的运行规则,通过这个规则可以避免类的非安全性问题和类被重复加载的问题,但他也遇到了一些问题,比如JNDI和JDBC不能通过这个规则进行加载,它需要打破双亲委派模型的方式来加载

机制

如果一个类加载器收到了类加载的请求,它首先不会去尝试加载这个类,而是把这个请求委派给父类加载器去完成。

每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围没有找到需要的类)时,子加载器才会尝试自己去完成加载,如果能找到就返回对象,若直到应用程序类加载器都无法加载这个类,则抛出ClassNotFound异常

1)启动类加载器是由C++实现的,用于加载<JAVA_HOME>/jre/lib/rt.jar 和 resources.jar等jar包结构(即标准库的目录lib目录)

2)扩展类加载器用于加载<JAVA_HOME>/jre/lib/ext目录下的jre包(JDK中一些扩展库对应的目录,lib或ext目录)

3)应用类程序加载器用于加载classpath,也就是用户的所有类的(用户自定义的类和第三方库对应目录)

优点
1、避免重复加载类

比如A类和B类都有一个父类C类,那么当A启动时就会将C类加载起来,那么在B类进行加载时就不需要再重复加载C类了

2、安全性

当使用双亲委派模型时,用户就不能伪造一些不安全的系统类了。比如jre已经提供了String类在启动类加载时加载,那么用户若再自定义一个不安全的String类时,按照双亲委派模型就不会再加载用户自定义的那个不安全的String类了,这样就可以避免非安全的问题发生了

打破双亲委任模型

双亲委派模型虽然有其优点,但在某些也存在一些问题,比如Java中SPI(Service Provider Interface,服务提供接口)机制中的JDBC实现

tomcat中加载webapp时就是用的自定义的类加载器,就只能在webapp指定目录中查找,若在这里找不到就不会再去标准库啥的地方找了,直接抛异常

三、JVM中的垃圾回收机制

        在C++中,动态分配内存管理允许程序在运行时分配和释放内存,相比静态内存管理(编译时确定内存分配大小),动态管理内存提供了更大的灵活性和控制能力。

        C++中的动态内存管理通过new和delete关键字进行手动管理,同时智能指针提供了更安全和高效的方式来管理动态分配的内存,帮助开发者避免内存泄漏等问题。

        相比C语言中的malloc分配内存,new不仅分配内存还进行了初始化。

        Java也使用了new来进行动态内存管理,但相比之下Java给出了一个方案解决内存泄漏问题—垃圾回收机制(GC),即让JVM自行判定某个内存是否不再使用,若不再使用则回收,此时就不必程序员手动写代码回收。

上面讲了Java运行时内存的各个区域,对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言,其生命周期与相关线程有关,随线程而生,随线程而灭。

并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。

因此讲内存分配何回收关注的是Java方法区这两个区域。

Java堆中存放着几乎所有的对象实例,垃圾回收器在对堆进行垃圾回收前,首先要判断这些对象哪些存活,哪些已经“死去”,判断对象是否已经”死去“有如下几种算法:

1、死亡对象的判断算法
1)引用计数算法

每个对象都有一个引用计数器,记录着有多少个引用指向该对象。当引用计数器为0时,表示该对象不再被任何引用指向,即认为该对象是死亡的,可以被垃圾回收器回收

实现简单,对垃圾对象的回收比较及时;但是难以处理循环引用,会导致引用计数器无法归零,从而造成内存泄漏

2)可达性分析算法

通过一组称为”GC Roots"的根对象作为起始点,从这些根对象开始往下搜索,可达的对象被认为是存活的,不可达的对象则是被判断为死亡,可以被回收

GC Roots:包括线程栈(本地变量表)、静态变量、常量池中的引用,它们保证了对象之间的可达性链条

能够有效处理循环引用的问题,不会导致内存泄漏;但是相对于计数算法,实现和运行时开销较大

        在Java中,主流的垃圾回收器(如Serial, Parallel, CMS, G1等)通常使用可达性分析算法来判断对象的存活状态,这种算法能够更精确地确定不再使用的对象,从而安全有效地回收内存资源,提高程序性能和可靠性。

2、垃圾回收算法
1)标记-清除法

首先从根节点出发标记所有可达对象,再清除所有未标记对象(即不可达对象)

简单粗暴,适用于处理大对象和长时间存活的对象,但可能导致内存碎片化,影响内存分配效率

2)复制算法

将堆内存分为两块,每次只使用其中一块,当其中一块内存被占满时,将存活对象复制到另一块内存中,然后清除原内存中的所有对象

适用于处理短生命周期的对象,能够有效避免内存碎片化,但会消耗一定的内存空间

3)标记-整理法

类似于标记-清除法,但在清除阶段会将存活对象向一端移动,然后直接清除边界外的所有对象。这样可以保持存活对象的持续性,减少内存碎片化

适用于处理长时间存活对象和避免内存碎片化,但需要额外的移动存活对象的操作

4)分代算法

根据对象的存货周期将堆内存划分为不同的代,通常分为新生代和老生代。针对不同代使用不同的垃圾回收算法,如新生代使用复制算法,老生代使用标记-清除或标记-整理算法

充分利用对象的存活特性,提高垃圾回收效率,减少对整个内存的扫描次数

        在实际应用中,Java的垃圾回收器通常会根据应用程序的特性和运行环境的不同,结合多种垃圾回收算法,采用分代收集和并发收集等技术,以达到最佳的垃圾回收效果。不同的垃圾回收器(如Serial, Parallel, CMS, G1等)会选择不同的算法组合和优化策略,以满足不同的性能和响应时间需求。

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

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

相关文章

Linux 驱动开发究竟在开发什么?

文章目录 1 Linux 驱动开发架构图2 更具体的例子&#xff1a;LED 驱动程序2.1 硬件层&#xff08;Hardware Layer&#xff09;2.2 固件层&#xff08;Firmware Layer&#xff09;2.3 驱动程序层&#xff08;Driver Layer&#xff09;2.4 操作系统内核&#xff08;Kernel Layer&…

【全国大学生电子设计竞赛】2021年A题

&#x1f970;&#x1f970;全国大学生电子设计大赛学习资料专栏已开启&#xff0c;限时免费&#xff0c;速速收藏~

2024年睿抗机器人开发者大赛(RAICOM)国赛题解

目录 RC-u1 大家一起查作弊 分数 15 RC-u2 谁进线下了&#xff1f;II 分数 20 RC-u3 势均力敌 分数 25 RC-u4 City 不 City 分数 30 RC-u5 贪心消消乐 分数 30 RC-u1 大家一起查作弊 分数 15 简单模拟题&#xff0c;对于多行读入使用while(getline(cin…

切割 Nginx 日志

目录 方式一&#xff1a;自定义脚本 方式二&#xff1a;logrotate crontab 讲解 centos 容器安装 crontab centos 容器 systemctl 命令执行异常 切割理由&#xff1a;假设一个网站访问量特别大&#xff0c;每天 access_log 文件有 2 个 G&#xff0c;如果想从文件中查找…

基于QCustomPlot实现色条(ColorBar)

一、简介 通过QCustomPlot实现ColorBar&#xff0c;直观显示各个位置的异常情况。实现效果如下&#xff0c; 二、源码 CPColorBar.hpp // CPColorBar.hpp #pragma once #include "qcustomplot.h"#include <QHash>class QCP_LIB_DECL CPColorBarData { pub…

使用 MRI 构建的大脑连接网络预测帕金森病萎缩进展模式| 文献速递-基于深度学习的乳房、前列腺疾病诊断系统

Title 题目 Brain Connectivity Networks Constructed Using MRI for Predicting Patterns of Atrophy Progression in Parkinson Disease 使用 MRI 构建的大脑连接网络预测帕金森病萎缩进展模式 Background 背景 Whether connectome mapping of structural and across …

全志T527-TP9930-Camera

一、简介 1、TP9930 TP9930 驱动模块主要实现将 4 路的 Camera 的数据转换为 BT656/BT1120 数据&#xff0c;从而实现在 T527 端来对数据进行处理和送显。 2、BT656/BT1120简介 BT656主要是针对PAL/NTSC等标清视频。随着高清视频的发展需要&#xff0c;又推出了BT1120标准&…

AI + Coding:可以有多少种玩法?

在当今快速发展的科技时代&#xff0c;人工智能&#xff08;AI&#xff09;和编程已经成为不可分割的两大领域。AI赋予了计算机更多的智能&#xff0c;使其能够处理复杂的数据、执行高级任务&#xff0c;而编程是实现这一切的基础。当AI与编程结合在一起时&#xff0c;会带来无…

图片懒加载与预加载(原生)

1、懒加载。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head>…

【开端】JAVA Mono<Void>向前端返回没有登陆或登录超时 暂无权限访问信息组装

一、绪论 JAVA接口返回信息ServerHttpResponse response 等登录接口token过期时需要给前端返回相关状态码和状态信息 二、Mono<Void>向前端返回没有登陆或登录超时 暂无权限访问信息组装 返回Mono对象 public abstract class Mono<T> implements CorePublisher…

2024最新Mysql事务原理与优化最佳实践

概述 我们的数据库一般都会并发执行多个事务&#xff0c;多个事务可能会并发的对相同的一批数据进行增删改查操作&#xff0c;可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。 这些问题的本质都是数据库的多事务并发问题&#xff0c;为了解决多事务并发问题&…

在java中通过subString方法来截取字符串中的文本

1、subString&#xff08;&#xff09;常规用法可以通过下标来进行获取&#xff0c;在java中是从0开始&#xff0c;前包括后不包括。 String str “Hello Java World!”; 用法一: substring(int beginIndex) 返回从起始位置&#xff08;beginIndex&#xff09;至字符串末尾…

供应链库存管理面临什么问题?全面解析安全库存和周转库存!

在当今这个快速变化的商业世界中&#xff0c;供应链管理已成为企业获取竞争优势的核心领域。库存管理&#xff0c;作为供应链中的关键环节&#xff0c;直接关系到企业的成本控制、客户服务水平以及市场响应速度。然而&#xff0c;面对市场竞争的加剧和客户需求的多变&#xff0…

事务性邮件调用接口如何配置灵活调用策略?

事务性邮件调用接口性能怎么优化&#xff1f;如何使用接口调用&#xff1f; 如何配置灵活调用策略&#xff0c;不仅可以提升邮件发送的效率和可靠性&#xff0c;还能增强用户体验。AokSend将详细介绍事务性邮件调用接口的配置方法和策略&#xff0c;以便企业在实际应用中取得最…

深度学习读书笔记(1)--机器学习、人工智能、深度学习的关系

声明&#xff1a;本文章是根据网上资料&#xff0c;加上自己整理和理解而成&#xff0c;仅为记录自己学习的点点滴滴。可能有错误&#xff0c;欢迎大家指正。 阅读的书籍主要为《UnderstandingDeepLearning》《动手学深度学习》 1956 年提出 AI 概念&#xff0c;短短3年后&…

【初阶数据结构题目】14.随机链表的复制

随机链表的复制 点击链接做题 思路&#xff1a; 浅拷贝&#xff1a;拷贝值 深拷贝&#xff1a;拷贝空间 在原链表的基础上继续复制链表置random指针复制链表和原链表断开 代码&#xff1a; /*** Definition for a Node.* struct Node {* int val;* struct Node *next…

【开发踩坑】windows查看jvm gc信息

windows查看jvm gc信息 EZ 找出java进程PID 控制面板----搜索任务管理器---- 任务管理器----搜索 java----详细信息 这里PID是4856 cmd jstat gc面板 reference&#xff1a; jstat命令

【Redis】缓存三大问题与缓存一致性问题

缓存三大问题 缓存穿透 缓存穿透是指用户查询的数据在缓存和数据库中都不存在&#xff0c;导致每次请求都会直接落到数据库上&#xff0c;增加数据库负载。 解决方案 1&#xff09;参数校验 一些不合法的参数请求直接抛出异常信息返回给客户端。比如查询的数据库 id 不能小于…

【letcod-c++】128.最长连续序列

一、题目 二、分析 第一想法是像“242字母异位词”那样用哈希数组&#xff0c;但是这个数组元素的范围比较广&#xff0c;元素又比较分散&#xff0c;用数组太浪费空间&#xff0c;不合适。 于是考虑用哈希set(unordered_set),这个时候忽然想到前几天学习到set它能自动排序且自…

MySQL笔记(九):存储引擎

一、介绍 二、演示 Memory的使用场景&#xff1a; 例如网吧&#xff0c;用户再次上线时会更新状态 #表类型和存储引擎-- 查看所有的存储引擎SHOW ENGINES; -- 1、innodb 支持事务&#xff0c;外键&#xff0c;行级锁-- 2、myisam CREATE TABLE t31(id INT,name VARCHAR(32)) …