【面试题】JVM部分[2025/1/13 ~ 2025/1/19]

news2025/1/21 6:33:36

JVM部分[2025/1/13 ~ 2025/1/19]

  • 1. JVM 由哪些部分组成?
  • 2. Java 的类加载过程是怎样的?
  • 3. 请你介绍下 JVM 内存模型,分为哪些区域?各区域的作用是什么?
  • 4. JVM 垃圾回收调优的主要目标是什么?
  • 5. 如何对 Java 的垃圾回收进行调优?
  • 6. 常用的 JVM 配置参数有哪些?
  • 7. Java 中常见的垃圾收集器有哪些?
  • 8. 垃圾收集算法
  • 9. 线上 CPU 飙高如何排查?
  • 10. 怎么分析 JVM 当前的内存占用情况?
  • 11. OOM 后怎么分析?

我的博客地址

1. JVM 由哪些部分组成?

  1. 组成
    • 类加载器子系统(ClassLoader)
    • 运行时数据区(Runtime Data Area)
    • 执行引擎(Execution Engine)
    • 本地方法接口(Native Interface,JNI)
  2. 执行流程
    首先需要准备编译好的 Java 字节码文件(即class文件)。
    然后需要先通过一定方式(类加载器)将 class 文件加载到内存中(运行时数据区)。
    又因为字节码文件是 JVM 定义的一套指令集规范,底层操作系统无法直接执行。
    因此需要特定的命令解释器(执行引擎)将字节码翻译成特定的操作系统指令集交给 CPU 去执行。
    这个过程中会需要调用到一些不同语言为 Java 提供的接口(例如驱动、地图制作等),这就用到了本地方法接口(Native Interface)。

2. Java 的类加载过程是怎样的?

  1. 加载: 将二进制流读入内存中,为了生成一个 Class 对象。
  2. 链接
    a. 验证: 主要是验证加载进来的二进制流是否符合一定格式,是否规范,是否符合当前 JVM 版本等等之类的验证。
    b. 准备: 为静态变量(类变量)赋初始值,也即为它们在方法区划分内存空间。这里注意是静态变量,并且是初始值,比如 int 的初始值是 0。
    c. 解析: 将常量池的符号引用转化成直接引用

    符号引用可以理解为只是个替代的标签,比如你此时要做一个计划,暂时还没有人选,你设定了个 A 去做这个事。然后等计划真的要落地的时候肯定要找到确定的人选,到时候就是小明去做一件事。解析就是把 A(符号引用) 替换成小明(直接引用)。符号引用就是一个字面量,没有什么实质性的意义,只是一个代表。
    直接引用指的是一个真实引用,在内存中可以通过这个引用查找到目标。

  3. 初始化: 这时候就执行一些静态代码块,为静态变量赋值,这里的赋值才是代码里面的赋值,准备阶段只是设置初始值占个坑。

3. 请你介绍下 JVM 内存模型,分为哪些区域?各区域的作用是什么?

  1. 程序计数器(Program Counter Register):每个线程都有自己的程序计数器,用于指示当前线程执行的字节码指令的行号,以便线程执行时能够回到正确的位置。
  2. 虚拟机栈(JVM Stack):也称为 Java 方法栈,用于存储方法执行时的局部变量表、操作数栈、动态链接、方法出口等信息。每个线程在执行一个方法时,都会为该方法分配一个栈帧,并将该栈帧压入虚拟机栈,当方法执行完毕后,虚拟机会将其出栈。
  3. 本地方法栈(Native Method Stack):与虚拟机栈类似,用于存储本地方法的执行信息。
  4. (Heap):用于存放所有线程共享的对象和数组,是垃圾回收的主要区域。
  5. 方法区(Method Area):用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也是被所有线程共享的。方法区具体实现永久代/元空间

程序计数器、虚拟机栈、本地方法栈是线程私有的,堆、方法区、运行时常量池是线程共享的。

4. JVM 垃圾回收调优的主要目标是什么?

GC 调优的核心思路就是尽可能的使对象在年轻代被回收,减少对象进入老年代。

  1. 吞吐量调优:主要关注降低垃圾回收的总时间,通过 Parallel Scavenge 和 Parallel Old 提高 CPU 使用效率。
  2. 延迟调优:关注最大停顿时间,通过 CMS、G1、ZGC 等收集器降低 STW 停顿时间。
  3. 堆大小调优:通过合理的堆内存分配和分代比例调优,避免频繁的 Minor GC 和 Full GC。

5. 如何对 Java 的垃圾回收进行调优?

  1. 思路
    分析Young GC 和 Full GC 触发频率、原因、晋升的速率、老年代内存占用量, 可以使用命令(jstat -gc [pid] [频率] [总次数])或监控页面查看
    例如: 如果发现频繁会产生 Full GC,分析日志之后发现没有内存泄漏,只是 Young GC 之后会有大量的对象进入老年代,然后最终触发 Ful GC。所以就能得知是 Survivor 空间设置太小,导致对象过早进入老年代,因此调大 Survivor 。

6. 常用的 JVM 配置参数有哪些?

  • -Xms:初始化堆内存大小
  • -Xmx:最大堆内存大小
  • -Xss:设置每个线程的栈大小
  • -XX:MetaspaceSize:初始化元空间大小
  • -XX:MaxMetaspaceSize:最大元空间大小
  • -XX:+HeapDumpOnOutOfMemoryError:当发生 OutOfMemoryError 时,生成堆转储(heap dump)文件
  • -XX:HeapDumpPath: 生成堆转储文件路径
  • -XX:+PrintGCDetails:打印详细的垃圾回收日志
  • -XX:+UseG1GC:启用G1垃圾收集器
  • -XX:+UseConcMarkSweepGC:启用CMS垃圾收集器
  • -XX:+UseZGC:启用ZGC(低延迟垃圾收集器)

7. Java 中常见的垃圾收集器有哪些?

  1. 新生代垃圾收集器
    • 1)Serial 收集器:
      • 单线程收集器,适合小型应用和单处理器环境。
      • 触发 Stop-The-World(STW)操作,所有应用线程在 GC 时暂停。
      • 适用场景:适用于单线程应用和客户端模式。
    • 2)ParNew 收集器:
      • 是 Serial 收集器的多线程版本,能够并行进行垃圾收集。
      • 与 CMS 收集器配合使用时,通常会选择 ParNew 收集器作为新生代收集器。
      • 适用场景:适用于多处理器环境,通常配合 CMS 收集器使用。
    • 3)Parallel Scavenge 收集器(吞吐量优先):
      • 也称为 “吞吐量收集器”,追求最大化 CPU 时间的利用率。
      • 并行处理新生代垃圾回收,适合大规模后台任务处理,注重吞吐量而非延迟。
      • 适用场景:适用于大规模运算密集型后台任务,适合对吞吐量要求较高的场景。
  2. 老年代垃圾收集器:
    • 1)Serial Old 收集器:
      • Serial 收集器的老年代版本,使用标记-整理(Mark-Compact)算法进行垃圾回收。
      • 适用场景:适合单线程环境和低内存使用场景,通常配合 Serial 收集器一起使用。
    • 2)Parallel Old 收集器:
      • Parallel Scavenge 收集器的老年代版本,使用多线程并行标记-整理算法。
      • 适用场景:适合大规模并行计算的场景,适用于高吞吐量要求的任务。
    • 3)CMS(Concurrent Mark-Sweep)收集器:
      • 并发标记-清除收集器,追求低延迟,减少 GC 停顿时间。
      • 使用并发标记和清除算法,适合对响应时间有较高要求的应用。
      • 缺点:可能会产生内存碎片,并且在并发阶段可能会发生 Concurrent Mode Failure,导致 Full GC。
      • 适用场景:适用于对响应时间要求高的应用,如 Web 服务和电商平台。
    • 4)G1(Garbage First)收集器:
      • 年轻代采用类似于传统的复制算法, 老年代采用标记整理算法
      • 设计用于取代 CMS 的低延迟垃圾收集器,能够提供可预测的停顿时间。
      • 通过分区来管理内存,并在垃圾收集时优先处理最有价值的区域,避免了 CMS 的内存碎片问题。
      • 适用场景:适合大内存、多 CPU 服务器应用,尤其在延迟和响应时间敏感的场景中表现出色。
    • 5)ZGC(Z Garbage Collector)收集器:
      • 低停顿、高吞吐量的垃圾收集器,停顿时间一般不会超过 10 毫秒。
      • 适用场景:适用于需要管理大堆内存且对低延迟要求极高的应用。

8. 垃圾收集算法

  1. 标记-清除算法(Mark-Sweep):
    • 主要用于 CMS,标记存活对象后,清除不可达对象,但容易产生内存碎片。
    • 工作原理:首先遍历堆中的对象,标记出所有的存活对象,接着清除未标记的对象。
    • 优点:实现简单,能够处理堆中的所有对象。
    • 缺点:标记和清除的过程会产生内存碎片,影响后续内存分配的效率。
  2. 标记-整理算法(Mark-Compact):
    • 用于 G1 和 Parallel Old,标记存活对象后进行整理,避免内存碎片。
    • 工作原理:首先标记出所有存活的对象,然后将存活的对象整理到一边,最后清除未标记的对象。
    • 优点:避免了内存碎片问题。
    • 缺点:整理阶段需要移动对象,会导致额外的开销。
  3. 复制算法(Copying):
    • 工作原理:将内存分成两部分,每次只使用其中一半,垃圾回收时将存活的对象从一半复制到另一半,清除原区域的所有对象(朴素的复制算法是这样的,实际使用会分为两个 survivor 和一个 eden 区)。
    • 优点:无需处理内存碎片,分配效率高。
    • 缺点:需要双倍的内存空间,浪费了一半的空间。

9. 线上 CPU 飙高如何排查?

  1. 首先确认哪个进程占用 CPU 过高,登录服务器利用 top 命令查看。
    top 命令是 Linux 下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于 Windows 的任务管理器
  2. 确认 CPU 利用率很高的进程的 PID,假设为 1234 确实是 Java 进程,则通过 top -Hp 1234 查看具体的线程。
  3. 假设得到的线程 ID 是 5678,再将线程转为十六进制。可以使用 printf "%x\n" 5678
  4. 得到十六进制的 tid 为 162e,此时在利用 jstack 1234 | grep 162e -A 100 查看具体的栈信息。
  5. 根据堆栈信息就可以定位到具体是哪行代码导致了 CPU 飙高,对应分析修复即可!

10. 怎么分析 JVM 当前的内存占用情况?

  1. 利用 jstat 监控和分析 JVM 内部的垃圾回收、内存等运行状态。可以用它来查看堆内存、非堆内存等的实时状态。使用命令 jstat -gc [pid] [频率] [总次数]
  2. 可以使用 jmap 查看, JVM 堆的详细信息(包括堆的配置、内存使用情况、GC 活动等)。\
  3. 阿里 arthas 使用
    • dashboard: 可以查看当前系统的实时数据面板。数据面板默认5秒刷新一次。可以 输入Q 后回车 或 Ctrl+C 退出dashboard命令。
    • thread: 后面加上线程ID会打印线程的栈。Arthas支持管道,可以用 thread 1 | grep ‘main(’ 查找到arthas-demo应用的main class。
    • sc: 用来查找JVM里已加载的类。例如查看名称为MathGame的类:sc -d *MathGame
    • jad: 用来反编译代码 。例如查看MathGame类的源代码:jad demo.MathGame
    • watch: 可以查看函数的参数/返回值/异常信息。例如查看MathGame类中primeFactors函数的返回值:watch demo.MathGame primeFactors returnObj ,每次函数被调用都会打印返回值,可以 输入Q 后回车 或 Ctrl+C 退出watch命令。

11. OOM 后怎么分析?

在发生 OOM 时,可以根据 jmap 得到堆转储文件(建议增加JVM启动参数,-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof,在发生 OOM 后自动生成转储文件),再导入到 MAT、VisualVM、GCeasy等工具中分析文件,找出哪些对象占用了大量的内存,再定位到具体的代码解决问题。

OOM内存泄露常见问题:

  1. 堆内存溢出(Java Heap Space)
    • Java 堆用于存放对象实例,如果创建了过多对象,或有内存泄漏导致对象无法被垃圾回收,堆内存就会耗尽。 如果有大量创建对象或集合类的场景,持续增加数据但未释放就会产生堆内存溢出。
    • 错误信息:java.lang.OutOfMemoryError: Java heap space
    • 解决方法:检查对象创建逻辑,确保及时释放无用对象,或增大堆内存大小(-Xmx 参数)。
  2. 栈内存溢出(StackOverflowError)
    • 每个线程都有独立的栈空间,栈用于存储方法调用的信息(局部变量、方法参数、返回地址等)。如果方法调用层次过深或存在无限递归,栈空间耗尽就会导致栈溢出。 常见于递归方法没有正确的退出条件、深层嵌套的方法调用场景。
    • 错误信息:java.lang.StackOverflowError
    • 解决方法:检查递归条件,优化递归算法或增加栈空间(-Xss 参数)。
  3. 方法区或元空间溢出(Metaspace / PermGen space)
    • 在 Java 8 之前,方法区被实现为永久代(PermGen),用于存放类的元数据(类信息、方法信息、常量池等)。在 Java 8 之后,永久代被替换为元空间(Metaspace),用本地内存实现。在频繁加载和卸载类的情况下(如使用大量动态生成的代理类或频繁热部署),可能导致方法区或元空间溢出。常见于使用动态代理频繁生成类、大量反射调用或频繁热部署场景。
    • 错误信息: Java 7 及之前:java.lang.OutOfMemoryError: PermGen space;Java 8 及之后:java.lang.OutOfMemoryError: Metaspace
    • 解决方法:增加元空间大小(-XX:MaxMetaspaceSize);优化代码以减少类加载和反射的频率。
  4. 直接内存溢出(Direct Buffer Memory)
    • Java NIO 使用直接内存(Direct Memory)来加快 I/O 操作,该内存不受 JVM 堆内存的限制。如果分配过多的直接内存,超过了设置的最大值,也会导致内存溢出。 常见于使用 NIO 操作 ByteBuffer 分配大量直接内存,或者 Netty 等框架中频繁使用直接内存场景。
    • 错误信息:java.lang.OutOfMemoryError: Direct buffer memory
    • 解决方法:检查直接内存的分配和释放情况,增加直接内存大小限制(-XX:MaxDirectMemorySize),或避免过多使用直接内存。
  5. 线程数过多导致的内存溢出(Unable to Create New Native Thread)
    • 每个线程都需要栈空间和一定的操作系统资源。如果创建过多线程而超出操作系统的资源限制,可能无法再创建新的线程,导致 OOM。 常见于创建大量线程或线程池大小过大。
    • 错误信息:java.lang.OutOfMemoryError: Unable to create new native thread
    • 解决方法:减少线程数,合理设置线程池的大小,避免无限制地创建新线程。
  6. GC 执行耗时过长导致的 OOM(GC Overhead Limit Exceeded)
    • 当 JVM 在垃圾回收上花费的时间过多且回收的内存不足以满足需要,JVM 会抛出 GC Overhead Limit Exceeded 错误,以避免长时间的垃圾回收循环。通常发生在堆内存接近耗尽但又无法完全释放的情况下。常见于对象频繁创建和销毁导致 GC 频繁触发,内存不足导致 GC 效率低下场景。
    • 错误信息:java.lang.OutOfMemoryError: GC overhead limit exceeded
    • 解决方法:增大堆内存,优化代码以减少短生命周期对象的创建,或调整垃圾回收策略。

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

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

相关文章

【Django】多个APP设置独立的URL

目录 方法一:各个App下设置自己的URL 1、在各自的App当中创建urls.py文件​编辑 2、在主urls当中包含子url 3、各App的urls中设置url 4、设置后台函数 5、最终结果 总结: 方法二:利用as方法,在总的URL中对views重命名 实…

函数递归的介绍

1.递归的定义 在C语言中,递归就是函数自己调用自己 上面的代码就是 main 函数在函数主体内 自己调用自己 但是,上面的代码存在问题:main 函数反复地 自己调用自己 ,不受限制,停不下来。 最终形成死递归,…

四、华为交换机 STP

生成树协议(STP)的核心目的是在存在冗余链路的网络中,构建一个无环的拓扑结构,从而防止网络环路带来的广播风暴等问题 一、STP 原理 选举根桥:网络中的每台交换机都会有一个唯一的桥 ID(BID)&am…

前端炫酷动画--图片(一)

目录 一、四角线框的跟随移动 二、元素倒影(-webkit-box-reflect) 三、模特换装(maskblend) 四、元素平滑上升 五、无限视差滚动 六、判断鼠标进入方向(轮播方向) 七、环形旋转效果 八、黑白小球交替旋转 九、hover时圆形放大 十、画一棵随机树(canvas) 十一、代码雨…

AI刷题-病毒在封闭空间中的传播时间

目录 问题描述 输入格式 输出格式 解题思路: 问题理解 数据结构选择 算法步骤 代码实现: 1.初始化: 2.设置边界条件: 3.判断 4.更新: 5.返回 最终的实现代码如下: 运行结果: …

SQL表间关联查询详解

简介 本文主要讲解SQL语句中常用的表间关联查询方式,包括:左连接(left join)、右连接(right join)、全连接(full join)、内连接(inner join)、交叉连接&…

路由器旁挂三层网络实现SDWAN互联(爱快SD-WAN)

近期因公司新办公区建设,原有的爱快路由器的SDWAN功能实现分支之间互联的服务还需要继续使用。在原有的小型网络中,使用的爱快路由器当作网关设备,所以使用较为简单,如下图所示。 现变更网络拓扑为三层网络架构,但原有的SDWAN分支…

麦田物语学习笔记:制作[SceneName]Attribute特性

基本流程 因为在现有的项目中,像开始场景的切换或者Telepot组件都需要手动输入场景名,有时还可能键入出错,而该特性能用选择的方式去解决这一问题 1.代码实现 SceneNameDrawer.cs //参数绘制 using UnityEditor; using UnityEngine; #if UNITY_EDITOR [CustomPropertyDrawer(…

HTML之拜年/跨年APP(改进版)

目录: 一:目录 二:效果 三:页面分析/开发逻辑 1.页面详细分析: 2.开发逻辑: 四:完整代码(不多废话) index.html部分 app.json部分 二:效果 三:页面…

【2024 年度总结】从小白慢慢成长

【2024 年度总结】从小白慢慢成长 1. 加入 CSDN 的契机2. 学习过程2.1 万事开头难2.2 下定决心开始学习2.3 融入技术圈2.4 完成万粉的目标 3. 经验分享3.1 工具的选择3.2 如何提升文章质量3.3 学会善用 AI 工具 4. 保持初心,继续前行 1. 加入 CSDN 的契机 首次接触…

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用

一文大白话讲清楚webpack基本使用——2——css相关loader的配置和使用 1. 建议按文章顺序从头看是看 第一篇:一文大白话讲清楚啥是个webpack第二篇:一文大白话讲清楚webpack基本使用——1——完成webpack的初步构建然后看本篇,Loader的配置…

如何将 session 共享存储到 redis 中

文章目录 一. 分布式 session 登录1.1 什么是分布式?1.2 Session 共享1.3 为什么服务器 A 登录后,请求发到服务器 B,不认识该用户?1.4 共享存储 二. Session 共享实现Redis三. 测试session共享四. cookie设置4.1 前端4.2 后端 一.…

Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化

Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化 源数据库Kafka Connect监控测试结果 源数据库 Oracle 19c,本地,CDB数据库主机的I/O带宽为6 GB/s,由此主机上运行的所有数据库共享临时表空间由42个文件组成&#x…

STM32 FreeROTS Tickless低功耗模式

低功耗模式简介 FreeRTOS 的 Tickless 模式是一种特殊的运行模式,用于最小化系统的时钟中断频率,以降低功耗。在 Tickless 模式下,系统只在有需要时才会启动时钟中断,而在无任务要运行时则完全进入休眠状态,从而降低功…

Redis - General - 未授权访问漏洞(用户配置问题)

0x01:产品简介 Redis(Remote Dictionary Service,远程数据服务),是一款开源的基于内存的键值对存储系统,其主要被用作高性能缓存服务器使用(比如作为消息中间件和用于 Session 共享&#xff09…

学习threejs,使用OrbitControls相机控制器

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.OrbitControls 相机控…

SQL和MySQL以及DAX的日期表生成?数字型日期?将生成的日期表插入到临时表或者实体表中

几种生成日期表的方法 如何用SQL语句生成日期表呢? 如何用MySQL语句生成日期表呢? 如何用DAX语句生成日期表呢? 1. MySQL生成日期表 1.1 日期格式:yyyy-MM-dd 字符型 2024-01-02 -- 生成日期表 WITH RECURSIVE temp_dateTable …

C# 动态创建Label和ComboBox控件并修改Text

背景:在做项目的时候可能需要根据一定数量创建某些控件并修改其属性,本文以控件label、ConboBox控件进行动态创建。 程序运行前后的的Form动态图 代码如下: using System; using System.Collections.Generic; using System.ComponentModel; …

2025年编程语言热度分析:Python领跑,Go与Rust崛起

TIOBE Index(TIOBE 编程语言指数)是一个衡量编程语言流行度的排名系统。它通过分析多种搜索引擎、在线编程社区、技术论坛、问答网站(如 Google、Bing、Yahoo、Wikipedia、Stack Overflow)等的搜索和讨论数据,评估不同…

【从零开始入门unity游戏开发之——C#篇46】C#补充知识点——命名参数和可选参数

考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、…