Java虚拟机面试题精选(二)

简介: 现在面试Java开发时,基本都会问到Java虚拟机的知识,根据职位不同问的内容深浅又有所区别。本文整理了10道面试中常问的Java虚拟机面试题,希望对正在面试的同学有所帮助。

概述


现在面试Java开发时,基本都会问到Java虚拟机的知识,根据职位不同问的内容深浅又有所区别。本文整理了10道面试中常问的Java虚拟机面试题,希望对正在面试的同学有所帮助。

 

11.介绍下垃圾收集机制(在什么时候,对什么,做了什么)?


在什么时候?


在触发GC的时候,具体如下,这里只说常见的Young GCFull GC

触发Young GC:当新生代中的Eden区没有足够空间进行分配时会触发Young GC

触发Full GC

1.    当准备要触发一次Young GC时,如果发现统计数据说之前Young GC的平均晋升大小比目前老年代剩余的空间大,则不会触发Young GC而是转为触发Full GC。(通常情况)

2.    如果有永久代的话,在永久代需要分配空间但已经没有足够空间时,也要触发一次Full GC

3.    System.gc()默认也是触发Full GC

4.    heap dumpGC默认也是触发Full GC

5.    CMS GC时出现Concurrent Mode Failure会导致一次Full GC的产生。


对什么?


对那些JVM认为已经死掉的对象。即从GC Root开始搜索,搜索不到的,并且经过一次筛选标记没有复活的对象。


做了什么?


对这些JVM认为已经死掉的对象进行垃圾收集,新生代使用复制算法,老年代使用标记-清除和标记-整理算法。

 

12.GC Root有哪些?


Java语言中,可作为GC Roots的对象包括下面几种:

·       虚拟机栈(栈帧中的本地变量表)中引用的对象。

·       方法区中类静态属性引用的对象。

·       方法区中常量引用的对象。

·       本地方法栈中JNI(即一般说的Native方法)引用的对象。

 

13.发生Young GC的时候需要扫描老年代的对象吗?


在分代收集中,新生代的规模一般都比老年代要小许多,新生代的收集也比老年代要频繁许多,如果回收新生代时也不得不同时扫描老年代的话,那么Young GC的效率可能下降不少。显然是不可能区扫描老年代的,那么是通过什么办法来解决这个问题了?

在大多垃圾收集器中(G1有不同的地方),通过CardTable来维护老年代对年轻代的引用,CardTable可以说是Remembered SetRS)的一种特殊实现,是Card的集合。Card是一块2的幂字节大小的内存区域,例如HotSpot512字节,里面可能包含多个对象。CardTable要记录的是从它覆盖的范围出发指向别的范围的指针。以分代式GCCardTable为例,要记录老年代指向年轻代的跨代指针,被标记的Card是老年代范围内的。当进行年轻代的垃圾收集时,只需要扫描年轻代和老年代的CardTable即可保证不对全堆扫描也不会有遗漏。CardTable通常为字节数组,由Card的索引(即数组下标)来标识每个分区的空间地址。

 

14.垃圾收集器有哪些?


目前HotSpot中有7种作用于不同分代的收集器,如下图所示,如果两个收集器之间存在连线,就说明它们可以搭配使用。

image.png


15.介绍CMS垃圾收集器的特点?


CMSConcurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。


从名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于标记清除算法实现的,它的运作过程可以分为6个步骤,包括:初始标记、并发标记、预处理、重新标记、并发清除、重置。


CMS是一款优秀的收集器,它的主要优点在名字上已经体现出来了:并发收集、低停顿,但是CMS还远达不到完美的程度,它有以下3个明显的缺点:


1.    CMS收集器对CPU资源非常敏感。

2.    CMS收集器无法处理浮动垃圾(Floating Garbage),可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。

3.    CMS是一款基于标记清除算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。

了解CMS更多内容,查看我的另一篇文章:Java虚拟机:垃圾收集原理和垃圾收集器

 

16.介绍下G1垃圾收集器的特点?(较复杂,可以考虑跳过)


G1(Garbage-First)收集器是当今收集器技术发展的最前沿成果之一。G1是一款面向服务端应用的垃圾收集器。与其他GC收集器相比,G1具备如下特点:并行与并发、分代收集、空间整合、可预测的停顿。


G1之前的其他收集器进行收集的范围都是整个新生代或者老年代,而G1不再是这样。使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域,虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。


G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的来由)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽可能高的收集效率。


Mixed GCG1垃圾收集器特有的收集方式,Mixed GC大致可划分为全局并发标记(global concurrent marking)和拷贝存活对象(evacuation)两个大部分:

global concurrent marking是基于SATB形式的并发标记,包括以下4个阶段:初始标记(Initial Marking)、并发标记(Concurrent Marking)、最终标记(Final Marking)、清理(Clean Up)。Evacuation阶段是全暂停的。它负责把一部分region里的活对象拷贝到空region里去,然后回收原本的region的空间。


了解G1更多内容,查看我的另一篇文章:Java虚拟机:垃圾收集原理和垃圾收集器

 

17.类加载的过程。


类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证、准备、解析3个部分统称为连接。


加载:


类加载过程的一个阶段,在加载阶段,虚拟机需要完成以下3件事情:

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

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

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


验证:


连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。从整体上看,验证阶段大致上会完成下面4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证。


准备:


该阶段是正式为类变量(static修饰的变量)分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这里所说的初始值通常情况下是数据类型的零值,下表列出了Java中所有基本数据类型的零值。

image.png


解析:


该阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。


初始化:


初始化阶段是执行类构造器<clinit>()方法的过程。<clinit>()方法是由编译器自动收集类中的所有类变量(static修饰的变量)的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。如果该类存在父类,则虚拟机会保证在执行子类的<clinit>()方法前,父类的<clinit>()方法已经执行完毕。因此在虚拟机中第一个被执行<clinit>()方法的类肯定是java.lang.Object

 

18.Java虚拟机中有哪些类加载器?


Java虚拟机的角度来讲,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另一种就是所有其他的类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader


Java开发人员的角度来看,绝大部分Java程序都会使用到以下3种系统提供的类加载器。


启动类加载器(Bootstrap ClassLoader):


这个类加载器负责将存放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。


扩展类加载器(Extension ClassLoader):


这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。


应用程序类加载器(Application ClassLoader):


这个类加载器由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。


我们的应用程序都是由这3种类加载器互相配合进行加载的,如果有必要,还可以加入自己定义的类加载器。这些类加载器之间的关系一般如图所示。

image.png

 

 

19.什么是双亲委派模型?


如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

 

20.使用双亲委派模型的好处?



使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java 类型体系中最基础的行为也就无法保证,应用程序也将会变得一片混乱。

 

 

—————END—————

相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
86 2
|
2月前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
83 14
|
2月前
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
2月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
2月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
28天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
2月前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
2月前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
37 6
|
2月前
|
存储 算法 安全
JVM常见面试题(四):垃圾回收
堆区域划分,对象什么时候可以被垃圾器回收,如何定位垃圾——引用计数法、可达性分析算法,JVM垃圾回收算法——标记清除算法、标记整理算法、复制算法、分代回收算法;JVM垃圾回收器——串行、并行、CMS垃圾回收器、G1垃圾回收器;强引用、软引用、弱引用、虚引用
|
2月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。