JVM高频面试题(2023最新版)
JVM面试题
1、JVM内存区域
Jvm包含两个子系统和两个组件。
1.1子系统
Class loader(类加载器):根据给定的全限定名类名(java.lang.object)来装载class文件到Runtime data area(运行时数据区)的method(方法区)。
Execution engine(执行引擎):执行classes中的指令。
Native Interface(本地接口):与native libraries交互,是其他编程语言交互的接口。
Runtime data area(运行时数据区域):JVM内存
作用:
- 通过编译器将Java代码转换为字节码
- 类加载器(class loader)再将字节码加载到内存中(运行时数据区)的方法区(method)
- 字节码文件只是JVM的一套指令集规范,不能直接交给底层操作系统执行,需要特定的命令解析器执行引擎(Execution engine),将字节码翻译成底层系统指令
- 再交给CPU执行
- 过程中需要调用其他语言的本地库接口(native interface)实现整个程序的功能
类的加载:将class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆上创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。
1.2 运行时数据区
程序计数器:当前线程所执行的字节码的行号指示器。通过改变这个计数器的值,选取下一条需要执行的字节码指令。
Java虚拟机栈:存储局部变量表、操作数栈、动态连接、方法出口等信息。(服务JAVA方法)
本地方法栈:为虚拟机Native方法服务的,这些方法底层是C语言编写,直接与操作系统对接的方法。
堆:内存中最大的一块,被所有线程共享,几乎所有对象实例都在这里分配内存。包括静态对象。
方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
1.2.1 堆和栈的区别
物理地址:
堆的物理地址分配对象是不连续的。性能较慢。在GC时考虑到不连续的分配,因此有各种算法(标记清除、复制、标记压缩、分代等)
栈使用的是数据结构中的栈,先进后出,物理地址分配时连续的,性能快。
内存分别:
堆因为分配不是连续的,分配的内存在运行期才确认,大小不固定。
栈是连续的,分配的内存大小在编译器就确认,大小是固定的。
存放的内容:
堆存放对象的实例和数组,更关注数据的存储。
栈存放局部变量,操作数栈,返回结果。更关注程序方法的执行。
可见度:
堆对于整个应用程序共享、可见。
栈只对于线程可见,线程私有。生命周期和线程相同。
1.2.2 队列和栈的区别
- 队列:入队,出队;栈:进栈,出栈。
- 队列是队尾入队,队头出队,先进先出,两边都可操作;栈是先进后出,进栈出栈都在栈顶进行。
1.2.3 对象的创建过程
- 虚拟机收到new指令,先检查常量池是否已加载对应的类
- 如果没有,先执行相应的类加载(java文件转class,存入运行时数据区),类加载通过后分配内存
- 若堆中的内存是绝对规整的,使用“指针碰撞”方式分配内存。
- 若不是规整的,从空闲列表中分配。
1.2.4 内存溢出异常
不再被使用的对象或变量一直被占据在内存中。理论上Java有GC垃圾回收机制,不再被使用的对象会被GC自动回收。但还是存在内存泄漏问题。
原因:长生命周期的对象持有短生命周期对象的引用就会导致内存泄漏。
2 垃圾收集器
2.1 垃圾回收机制
Java中,由虚拟机自行执行对象的内存释放。有一个垃圾回收线程,低优先级,在虚拟机空闲或当前堆内促不足时,触发执行,扫描那些没有被任何引用的对象,并将它们添加到需要回收的集合中,进行回收。
2.2 GC
Gabage Collection 垃圾收集,忘记或错误的内存回收会导致程序或系统的不稳定甚至崩溃。
Java提供的GC功能可以自动检测对象是否超过作用域,从而达到自动回收内存的目的。
垃圾回收的优点
- 编写程序时,不需要考虑内存管理问题
- Java中的对象不再有“作用域”的概念,只有引用的对象才有“作用域”
- 垃圾回收机制有效防止了内存泄漏,有效的使用可使用的内存
- 作为一个单独的低级别的线程运行,在不可预知的情况下对堆中已经死亡或长时间没有用过的对象进行清除和回收
- 程序员不能实时对某个对象或所有对象调用垃圾回收器进行回收
- 垃圾回收有分代复制、标记、增量垃圾回收
垃圾回收基本原理
对于GC来说,当对象被创建后,GC就开始监控这个对象的地址、大小、及使用情况。
通常,GC采用向图的方式记录和管理堆中的对象。通过确定哪些对象是“可达的”。当GC确定一些对象为“不可达”时,GC就有责任回收这些内存空间。
可以通过System.gc(),通知GC运行,但并不保证GC一定会运行。
怎么判断对象是否可以被回收?
- 引用计数器法:为每个对象创建一个引用计数,有对象引用时+1,引用被释放时-1,当计数器为0时,就可以回收了。但是不能解决循环引用的问题
- 可达性分析算法:GC Roots开始向下搜索,当一个对象到GC Roots没有任何引用链相连时,则证明可以被回收
2.3 垃圾回收算法
标记-清除法:标记无用的对象,进行清除。(其他算法几乎都是在其上进行改进)
优点:实现简单,不需要对象进行移动。
缺点:效率低,产生大量不连续的内存碎片,提高了垃圾回收的频率。
- 标记阶段:标记出可以回收的对象
- 清除阶段:回收被标记的对象所占用的空间
复制算法:将内存划分为两个相等的区域,每次只使用其中一个。每次遍历单个区域,将存活的对象复制到另一个区域,再清除当前区域。
优点:按顺序分配内存,运行效率高,不用考虑内存碎片
缺点:可用的内存大小只要原来的一半,对存活率高的对象频繁复制
标记-整理算法:在新生代可以使用复制算法,老年代不适合(存活频率高)。标记整理算法在标记回收对象后,将所有存活的对象压缩到内存的一段,紧凑排列,再对边界外的内存进行回收。
优点:解决了标记清理算法存在内存碎片的问题
缺点:仍需要进行局部的对象移动,一定程度上降低了效率
分代收集算法:根据对象存活周期,将内存划分为几块:年轻代、老年代、永久代。(jdk1.8后,删除了永久代,增加了元数据区)
2.4 垃圾回收器
Serial收集器(复制算法):新生代单线程收集器,标记和清理都是单线程,优点是简单高效。收集器回收时会暂停业务线程。
ParNew收集器(复制算法):新生代并行收集器,Serial收集器的多线程版本,多核CPU环境下比Serial性能更好。GC线程和业务线程并行。
Parallel Scavenge(复制算法):新生代并行收集器,追求高吞吐量,高效利用CPU。尽快完成程序的运算任务。jdk1.8默认收集器。GC线程和业务线程并行。
Serial Old收集器 (标记-整理算法):老年代单线程收集器,Serial收集器的老年代版本。收集器回收时会暂停业务线程。
Parallel Old收集器(标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge的老年代版本。jdk1.8默认收集器。GC线程和业务线程并行。
CMS收集器(标记-清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,高并发、低停顿,追求最短GC回收停顿时间。牺牲了吞度量来获得最短的停顿时间,适用于服务器响应速度高要求的应用上。因为是基于标记-清除算法,会出现大量内存碎片,此时CMS会临时采用Serial Old回收器进行垃圾清除,同时性能会下降。GC线程和业务线程并行。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。
G1收集器(标记-整理算法):Java堆并行收集器,由jdk1.7提供,基于标记整理-算法,回收范围为整个堆,而不再分新生代和老年代。区域上使用了分区算法。一边清理一部分区域,一边占用一部分区域,特别大的对象放Humongous区域,也不够了开始FullGC。
ZGC(颜色算法):分区更灵活,逻辑上部分带。每次找到特别满的区域进行清除。
垃圾回收器工作流程:
新生代:老年代=1:2
新生代使用复制-算法,本身也分三个区,Eden、To Survivor、From Survivor。默认8:1:1
- Eden+From Survivor存活的对象放入To Survivor
- 清空Eden+From Survivor分区
- From Survivor和To Survivor分区交换
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄都+1,当年龄达到15(默认的)时,升级为老年代,大的对象直接放入老年代。
老年代这边,当空间占用达到某一个阈值之后,触发Full GC,此时一般使用标记整理算法。
对象优先分配到新生代的Eden区,Eden区空间不够时,进行Minor GC,还不够,则分配到老年代。
Minor GC非常频繁,回收速度也快。大对象(需要大量连续内存空间的对象)直接进入老年代。
3、虚拟机类加载机制
3.1 简述
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、解析和初始化,最终形成虚拟机可以直接使用的Java类型。
3.2 JVM加载Class文件的原理机制:
隐式装载:程序运行过程中,碰到new等方式创建对象时,调用类装载器加载对应类到JVM中。
显示装载:通过class.forname()等方法,显示加载需要的类。
动态加载,保证基类完全加载,其他类需要的时候才加载。
3.3 类加载器
实现通过类的权限定名获取该类的二进制字节流的代码块
- 启动类加载器,加载Java核心类库,无法被程序直接引用。Java_HOME/lib/目录中的,被 -Xbootclasspath参数指定路径的类库。
- 扩展类加载器,加载Java的扩展库,Java虚拟机的实现会提供一个扩展库目录。JDK的安装目录的jre/lib/ext子目录(扩展目录)或Java. ext. dirs系统变量指定的路径中的所有类库。
- 系统类加载器,根据Java应用的类路径(ClassPath)来加载Java类。通常Java应用的类都是它加载的。可通过ClassLoader.getSystemClassLoader()获取它。
- 用户自定义类加载器,通过继承java.lang.ClassLoader类实现。
3.4 类装载的过程
- 加载:根据路径找到对应的class文件导入。
- 验证:检查加载的class文件的正确性。
- 准备:给类中的静态变量分配内存空间。
- 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。
- 初始化:对静态变量和静态代码块执行初始化工作。
3.5 双亲委派
如果一个类加载器收到了类加载的请求,首先不会自己去加载,
而是委派给父类加载器,这样所有的加载请求都会传到顶层的启动类加载器,
当父加载无法完成加载(搜索范围中没找到)时,子加载器才去尝试加载。
启动类加载器=》扩展类加载器=》系统类加载器=》自定义类加载器。
3.5.1 优点
- 避免类重复加载(唯一性),只会在一个类加载器加载。
- 安全性,保证Java核心类库的安全,比如自己又写了一个java.lang.String,优先会去加载核心类库中的。
- 为模块化开发提供了基础支持,如果使用多个第三方库,可能存在同名的类。使用双亲委派机制可以保证不同的类加载器只加载自己的类,避免类名冲突。
4、JVM调优
4.1 工具
JDK的bin目录下,自带了很多监控工具。
jconsole:用于对JVM中内存、线程和类等进行监控。
jvisualvm:内存快照、线程快照、程序死锁、监控内存变化、GC变化等。
4.2 参数
- -Xms2g:初始化推大小为 2g;
- -Xmx2g:堆最大内存为 2g;
- -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
- -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
- –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
- -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
- -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
- -XX:+PrintGC:开启打印 gc 信息;
- -XX:+PrintGCDetails:打印 gc 详细信息。
urvivor 比例为 8:2; - –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
- -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
- -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
- -XX:+PrintGC:开启打印 gc 信息;
- -XX:+PrintGCDetails:打印 gc 详细信息。
相关文章:

JVM高频面试题(2023最新版)
JVM面试题 1、JVM内存区域 Jvm包含两个子系统和两个组件。 1.1子系统 Class loader(类加载器):根据给定的全限定名类名(java.lang.object)来装载class文件到Runtime data area(运行时数据区)…...

webpack学习-7.创建库
webpack学习-7.创建库 1.暴露库1.1概念1.2验证1.2.1 不导出方法1.2.2 导出方法 2.外部化 lodash3.外部化的限制4.最终步骤5.使用自己的库5.1坑 6.总结 1.暴露库 这个模块学习有点坑。看名字就是把自己写的个包传到npm,而且还要在项目中使用到它,支持各种…...
MQTT - 笔记
1 Mosquitto 官网 https://mosquitto.org/ 2 Windows环境下安装配置Mosquitto服务及入门操作介绍 Windows环境下安装配置Mosquitto服务及入门操作介绍-CSDN博客 3 开源:MQTT安装与配置使用 【C++】开源:MQTT安装与配置使用_c++ mqtt-CSDN博客 4 一文搞懂Qt-MQTT开发...
Django 安装
各位小伙伴想要博客相关资料的话,关注公众号:chuanyeTry即可领取相关资料! Django 安装 在安装 Django 前,系统需要已经安装了 Python 的开发环境。 如果你还没有安装 Python,请先从 Python 官网 https://www.python…...

推荐一个vscode看着比较舒服的主题:Dark High Contrast
主题名称:Dark High Contrast (意思就是,黑色的,高反差的) 步骤:设置→Themes→Color Theme→Dark High Contrast 效果如下: 感觉这个颜色的看起来比较舒服。...
YCSB 测试表预分区
最近使用 YCSB 测试时,一直使用如下方法创建预分区: TABLE_NAME"usertable" REGIN_SPLITS$((510-1)) cat << EOF | sudo -u hbase hbase shell create ${TABLE_NAME}, cf, {SPLITS > (1..${REGIN_SPLITS}).map {|i| "user#{100…...
K8s 教程
一文让你全面了解K8s(Kubernetes) - 知乎 Install and Set Up kubectl on Linux | Kubernetes阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 留存一份地址...

python:改进型鳟海鞘算法(SSALEO)求解23个基本函数
一、改进型鳟海鞘算法SSALEO 改进型鳟海鞘算法(SSALEO)由Mohammed Qaraad等人于2022年提出。 参考文献:M. Qaraad, S. Amjad, N. K. Hussein, S. Mirjalili, N. B. Halima and M. A. Elhosseini, "Comparing SSALEO as a Scalable Larg…...
Hive-数据模型详解(超详细)
文章目录 一、Hive数据模型1. 概述2. 数据库和表(1) 创建数据库(2) 使用数据库(3) 创建表格(4) 查看表结构 3. 分区与桶(1) 分区(2) 桶 4. 数据加载与查询(1) 数据导入(2) 查询语句 5. 总结 一、Hive数据模型 1. 概述 Hive是基于Hadoop的数据仓库工具,它提供了类似…...
docker的常规使用总结
不安装docker下载镜像,或者下载异构镜像,模拟docker客户端 https://pull.7ii.win/ 1、启动docker服务 systemctl start docker 设置开机自启 systemctl enable docker 2、查看镜像 docker images --查看下载镜像架构 docker inspect 镜像名字 |…...

CSS 文字弹跳效果
鼠标移过去 会加快速度 <template><div class"bounce"><p class"text" :style"{animationDuration: animationDuration}">欢迎使用UniApp Vue3!</p></div> </template><script> export d…...

什么是动态IP?静态IP和动态IP有什么区别?
动态IP(Dynamic IP)和静态IP(Static IP)它是指在计算机网络中分配给设备的两种不同类型的IP地址。 动态IP是指每次设备连接到网络时,网络服务提供商(ISP)IP地址的动态分配。当设备重新连接到网络时,它可能会被分配到不同的IP地址。动态IP适用于传统的家…...

Linux 与 Shell
Linux系统的四部分:Linux系统的核心是内核。内核主要负责四种功能: 系统内存管理 操作系统内核的主要功能之一:内存管理。(物理内存 虚拟内存)内核通过硬盘上称为交换空间(swap space)的存储区…...

大数据-Hive练习-环比增长率、同比增长率、复合增长率
目录 🥙12.1 环比增长率 1. 概述 2. 公式 3. 示例 4.练习-需求:计算各类商品的月环比增长率 🥙12.2 同比增长率 1. 概述 2. 公式 3. 示例 4. 练习-需求:计算各类商品的月同比增长率 🥙12.3 复合增长率 1. 概述 2. 公式 3. 示例…...

C++ 考前难点总结
前言 后天考c,但这几天得甲流了,特别难受!复习c的时候复习着忘着,所以用csdn记录一下不熟悉的知识点,等后天考前再看一遍! 函数模板 #include <iostream>// 定义一个模板类 template <class T1…...

ARM 汇编语言知识积累
博文参考: arm中SP,LR,PC寄存器以及其它所有寄存器以及处理器运行模式介绍 arm平台根据栈进行backtrace的方法-腾讯云开发者社区-腾讯云 (tencent.com) 特殊功能寄存器: SP: 即 R13,栈指针,…...

k8s面试之——简述网络模型
kubernetes网络模型是kubernetes集群中管理容器网络通信的一种机制,用于实现pod间、pod与外部网络间的通信和互联,并提供了多种网络插件和配置选项来满足不同应用场景下的需求。kubernetes网络模型可以分为一下几个部分: 1. pod网络模型 在…...

C语言中关于if else的理解
if else我们可以理解为 if(条件1) //如果条件1成立 语句1; //执行语句1 else //如果条件1不成立 语句2; //执行语句2 这是一个经典的if els…...

Keil5软件仿真 定时器互补通道 波形输出(Logic Analyzer)
步骤一:管脚配置确认。 ①配置定时器的管脚模式为复用推挽输出模式(GPIO_MODE_AF_PP)!!!,注意:复用开漏模式软件仿真时无波形。 步骤二:编译程序。 ①点击编译按钮。 …...
华纳云:怎么实现Linux主机ssh无密码登录
实现Linux主机之间的SSH无密码登录可以通过使用SSH密钥对。以下是简单的步骤: 步骤 1: 生成SSH密钥对 打开终端,并在本地计算机上执行以下命令: ssh-keygen -t rsa 此命令将生成一对SSH密钥(公钥和私钥)。您可以选择在生成密钥时设置密码&…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...

Java中HashMap底层原理深度解析:从数据结构到红黑树优化
一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一,是基于哈希表的Map接口非同步实现。它允许使用null键和null值(但只能有一个null键),并且不保证映射顺序的恒久不变。与Hashtable相比,Hash…...