239 Star 2.1K Fork 87

鹏磊 / DevBooks

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
Jvm最新2021年面试题大汇总,附答案.md 13.05 KB
一键复制 编辑 原始数据 按行查看 历史

Jvm最新2023年面试题大汇总,附答案

全部答案,更新日期:2023年6月11日,直接下载吧!

下载链接:高清172份,累计 7701 页大厂面试题 PDF

1、GC Roots 有哪些?

1、 GC Roots 是一组必须活跃的引用。用通俗的话来说,就是程序接下来通过直接引用或者间接引用,能够访问到的潜在被使用的对象。

2、 GC Roots 包括:Java 线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等。也就是与我们栈帧相关的各种引用。所有当前被加载的 Java 类。Java 类的引用类型静态变量。运行时常量池里的引用类型常量(String 或 Class 类型)。JVM 内部数据结构的一些引用,比如 sun.jvm.hotspot.memory.Universe 类。用于同步的监控对象,比如调用了对象的 wait() 方法。JNI handles,包括 global handles 和 local handles。

3、 这些 GC Roots 大体可以分为三大类,下面这种说法更加好记一些:活动线程相关的各种引用。类的静态变量的引用。JNI 引用。

4、 有两个注意点:我们这里说的是活跃的引用,而不是对象,对象是不能作为 GC Roots 的。GC 过程是找出所有活对象,并把其余空间认定为“无用”;而不是找出所有死掉的对象,并回收它们占用的空间。所以,哪怕 JVM 的堆非常的大,基于 tracing 的 GC 方式,回收速度也会非常快。

2、说说Java 垃圾回收机制

在 Java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在 JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

3、介绍一下类文件结构吧!

魔数: 确定这个文件是否为一个能被虚拟机接收的 Class 文件。Class 文件版本 :Class 文件的版本号,保证编译正常执行。常量池 :常量池主要存放两大常量:字面量和符号引用。访问标志 :标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口,是否为 public 或者 abstract 类型,如果是类的话是否声明为 final 等等。当前类索引,父类索引 :类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了 java.lang.Object 之外,所有的 java 类都有父类,因此除了 java.lang.Object 外,所有 Java 类的父类索引都不为 0。接口索引集合 :接口索引集合用来描述这个类实现了那些接口,这些被实现的接口将按implents(如果这个类本身是接口的话则是extends) 后的接口顺序从左到右排列在接口索引集合中。字段表集合 :描述接口或类中声明的变量。字段包括类级变量以及实例变量,但不包括在方法内部声明的局部变量。方法表集合 :类中的方法。属性表集合 :在 Class 文件,字段表,方法表中都可以携带自己的属性表集合。

4、分代收集算法

当前主流 VM 垃圾收集都采用”分代收集” (Generational Collection)算法, 这种算法会根据对象存活周期的不同将内存划分为几块, 如 JVM 中的新生代、老年代、永久代, 这样就可以根据各年代特点分别采用最适当的 GC 算法

5、堆溢出的原因?

堆用于存储对象实例,只要不断创建对象并保证 GC Roots 到对象有可达路径避免垃圾回收,随着对象数量的增加,总容量触及最大堆容量后就会 OOM,例如在 while 死循环中一直 new 创建实例。

堆 OOM 是实际应用中最常见的 OOM,处理方法是通过内存映像分析工具对 Dump 出的堆转储快照分析,确认内存中导致 OOM 的对象是否必要,分清到底是内存泄漏还是内存溢出。

如果是内存泄漏,通过工具查看泄漏对象到 GC Roots 的引用链,找到泄露对象是通过怎样的引用路径、与哪些 GC Roots 关联才导致无法回收,一般可以准确定位到产生内存泄漏代码的具***置。

如果不是内存泄漏,即内存中对象都必须存活,应当检查 JVM 堆参数,与机器内存相比是否还有向上调整的空间。再从代码检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况,尽量减少程序运行期的内存消耗。

6、Tomcat是怎么打破双亲委派机制的呢?

是通过重写ClassLoader#loadClass和ClassLoader#findClass 实现的。可以看图中的WebAppClassLoader,它加载自己目录下的.class文件,并不会传递给父类的加载器。但是,它却可以使用 SharedClassLoader 所加载的类,实现了共享和分离的功能。

7、你知道哪些垃圾收集器?

序列号

最基础的收集器,使用复制算法、单线程工作,只用一个处理器或一条线程完成垃圾收集,进行垃圾收集时必须暂停其他所有工作线程。

Serial 是虚拟机在客户端模式的默认新生代收集器,简单高效,对于内存受限的环境它是所有收集器中额外内存消耗最小的,对于处理器核心较少的环境,Serial 由于没有线程交互开销,可获得最高的单线程收集效率。

新品

Serial 的多线程版本,除了使用多线程进行垃圾收集外其余行为完全一致。

ParNew 是虚拟机在服务端模式的默认新生代收集器,一个重要原因是除了 Serial 外只有它能与 CMS 配合。自从 JDK 9 开始,ParNew 加 CMS 不再是官方推荐的解决方案,官方希望它被 G1 取代。

并行清理

新生代收集器,基于复制算法,是可并行的多线程收集器,与 ParNew 类似。

特点是它的关注点与其他收集器不同,Parallel Scavenge 的目标是达到一个可控制的吞吐量,吞吐量就是处理器用于运行用户代码的时间与处理器消耗总时间的比值。

串行旧

Serial 的老年代版本,单线程工作,使用标记-整理算法。

Serial Old 是虚拟机在客户端模式的默认老年代收集器,用于服务端有两种用途:① JDK5 及之前与 Parallel Scavenge 搭配。② 作为CMS 失败预案。

平行老

Parallel Scavenge 的老年代版本,支持多线程,基于标记-整理算法。JDK6 提供,注重吞吐量可考虑 Parallel Scavenge 加 Parallel Old。

不育系

以获取最短回收停顿时间为目标,基于标记-清除算法,过程相对复杂,分为四个步骤:初始标记、并发标记、重新标记、并发清除。

初始标记和重新标记需要 STW(Stop The World,系统停顿),初始标记仅是标记 GC Roots 能直接关联的对象,速度很快。并发标记从 GC Roots 的直接关联对象开始遍历整个对象图,耗时较长但不需要停顿用户线程。重新标记则是为了修正并发标记期间因用户程序运作而导致标记产生变动的那部分记录。并发清除清理标记阶段判断的已死亡对象,不需要移动存活对象,该阶段也可与用户线程并发。

缺点:① 对处理器资源敏感,并发阶段虽然不会导致用户线程暂停,但会降低吞吐量。② 无法处理浮动垃圾,有可能出现并发失败而导致 Full GC。③ 基于标记-清除算法,产生空间碎片。

G1

开创了收集器面向局部收集的设计思路和基于 Region 的内存布局,主要面向服务端,最初设计目标是替换 CMS。

G1 之前的收集器,垃圾收集目标要么是整个新生代,要么是整个老年代或整个堆。而 G1 可面向堆任何部分来组成回收集进行回收,衡量标准不再是分代,而是哪块内存中存放的垃圾数量最多,回收受益最大。

跟踪各 Region 里垃圾的价值,价值即回收所获空间大小以及回收所需时间的经验值,在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间优先处理回收价值最大的 Region。这种方式保证了 G1 在有限时间内获取尽可能高的收集效率。

G1 运作过程:

初始标记:标记 GC Roots 能直接关联到的对象,让下一阶段用户线程并发运行时能正确地在可用 Region 中分配新对象。需要 STW 但耗时很短,在 Minor GC 时同步完成。

并发标记:从 GC Roots 开始对堆中对象进行可达性分析,递归扫描整个堆的对象图。耗时长但可与用户线程并发,扫描完成后要重新处理 SATB 记录的在并发时有变动的对象。

最终标记:对用户线程做短暂暂停,处理并发阶段结束后仍遗留下来的少量 SATB 记录。

筛选回收:对各 Region 的回收价值排序,根据用户期望停顿时间制定回收计划。必须暂停用户线程,由多条收集线程并行完成。

可由用户指定期望停顿时间是 G1 的一个强大功能,但该值不能设得太低,一般设置为100~300 ms。

8、JVM 选项 -XX:+UseCompressedOops 有什么作用?为什么要使用

当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。这也会对 CPU缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM主要动机在于可以指定最大堆大小,通过压缩OOP 可以节省一定的内存。通过-XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位的 OOP。

9、invokedynamic 指令是干什么的?

Java 7 开始,新引入的字节码指令,可以实现一些动态类型语言的功能。Java 8 的 Lambda 表达式就是通过 invokedynamic 指令实现,使用方法句柄实现。

10、动态改变构造

OSGi 服务平台提供在多种网络设备上无需重启的动态改变构造的功能。为了最小化耦合度和促使这些耦合度可管理, OSGi 技术提供一种面向服务的架构,它能使这些组件动态地发现对方。

11、怎样通过 Java 程序来判断 JVM 是 32 位 还是 64位?

12、引用计数法

13、在老年代-标记整理算法

14、Minor GC与Full GC分别在什么时候发生?

15、怎么获取 Java 程序使用的内存?堆使用的百分比?

16、在新生代-复制算法

17、JIT 是什么?

18、双亲委派模型是什么?

19、列举一些你知道的打破双亲委派机制的例子。为什么要打破?

20、谈谈你知道的垃圾回收算法

21、线上常用的 JVM 参数有哪些?

22、各种回收算法

23、JVM 有哪些运行时内存区域?

24、说说线程栈

25、JAVA8 与元数据

26、说说你知道的几种主要的JVM参数

27、生产环境用的什么JDK?如何配置的垃圾收集器?

28、本地方法栈的作用?

29、JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的

30、GC日志的real、user、sys是什么意思?

31、GC 是什么? 为什么要有 GC

全部答案,更新日期:2023年6月11日,直接下载吧!

下载链接:全部答案,整理好了

新增:高清PDF:172份,7701页,最新整理

Java
1
https://gitee.com/souyunku/DevBooks.git
git@gitee.com:souyunku/DevBooks.git
souyunku
DevBooks
DevBooks
master

搜索帮助