写点什么

24 道几乎必问的 JVM 面试题,我只会 7 道,你能答出几道?

用户头像
北游学Java
关注
发布于: 2021 年 06 月 09 日

前言

Java 语言的一个非常重要的特点就是与平台的无关性。而使用 Java 虚拟机是实现这一特点的关键,所以在面试 Java 岗的时候 JVM 几乎是必问的,所以今天我总结了 24 道 JVM 相对来说有代表性的面试题,希望对你有所帮助。



之前发过其他关于面试题的文章,然后有粉丝留言建议不要一开始就直接把答案贴出来,所以这篇文章我就先把题目放出来,答不出来的题可以翻一下放在后面的答案。


那话不多说,我们开始正题。




JVM 底层面试题

  • 说一下 JVM 的主要组成部分?及其作用?

  • 说一下 JVM 运行时数据区?

  • 队列和栈是什么?有什么区别?

  • 什么是双亲委派模型?

  • 说一下类装载的执行过程?

  • 怎么判断对象是否可以被回收?

  • Java 中都有哪些引用类型?

  • 说一下 JVM 有哪些垃圾回收算法?

  • 说一下 JVM 有哪些垃圾回收器?

  • 详细介绍一下 CMS 垃圾回收器?

  • 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

  • 简述分代垃圾回收器是怎么工作的?

  • 说一下 JVM 调优的工具?

  • 常用的 JVM 调优的参数都有哪些?

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

  • Java 中堆和栈有什么区别?

  • 你能保证 GC 执行吗?

JVM 底层与 GC(Garbage Collection)的面试题

  • 64 位 JVM 中,int 的长度是多数?

  • Serial 与 Parallel GC 之间的不同之处?

  • 32 位和 64 位的 JVM,int 类型变量的长度是多数?

  • Java 中 WeakReference 与 SoftReference 的区别?

  • WeakHashMap 是怎么工作的?

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

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

  • 32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数?

  • JRE、JDK、JVM 及 JIT 之间有什么不同?




JVM 底层面试题答案

1、说一下 JVM 的主要组成部分?及其作用?


**class loader 类加载器:**加载类文件到内存。Class loader 只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有 Exectution Engine 负责的。


**exection engine :**执行引擎也叫解释器,负责解释命令,交由操作系统执行。


**native interface:**本地接口。本地接口的作用是融合不同的语言为 java 所用。


**Runtimedata area 运行数据区:**运行数据区是 jvm 的重点,我们所有所写的程序都被加载到这里,之后才开始运行。


**stack:**栈也叫栈内存,是 java 程序的运行区,是在线程创建时创建,它的生命周期跟随线程的生命周期,线程结束栈内存释放;对于栈来说不存在垃圾回收的问题,只要线程一结束,该栈就结束。栈中的数据以栈帧的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法和运行期数据的集合,当一个方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2 栈帧,再弹出 F1 栈帧,遵循“先进后出”原则。


**堆内存:**一个 JVM 实例只存在一个堆内存,堆内存的大小是可以调节的。类的加载器读取了类文件之后,需要把类、方法、常变量放到堆内存中,以方便执行器执行,堆内存分三部分:永久存储(用于存放 jdk 自身携带的 class,interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载至此区域的数据是不会被垃圾回收掉的,只有关闭 jvm 释放此区域所占用的内存)区、新生区、老年代


**method area 方法区:**方法去是被所有线程共享,该区域保存的所有字段和字节方法码以及一些特殊方法如构造函数,接口代码也在此定义。


**PC Register 程序计数器:**每个线程都有一个程序计数器,就是一个指针,指向方法区中的方法字节码,由执行引擎读取下一条指令


2、说一下 JVM 运行时数据区?


不同虚拟机的运行时数据区可能略微有所不同,但都会遵从 Java 虚拟机规范, Java 虚拟机规范规定的区域分为以下 5 个部分:


程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;


Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;


本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;


Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;


方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。


3、队列和栈是什么?有什么区别?


  • 队列和栈都是被用来预存储数据的。

  • 队列允许先进先出检索元素,但也有例外的情况,Deque 接口允许从两端检索元素。

  • 栈和队列很相似,但它运行对元素进行后进先出进行检索。


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


在介绍双亲委派模型之前先说下类加载器。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在 JVM 中的唯一性,每一个类加载器,都有一个独立的类名称空间。类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。


类加载器分类:


  • 启动类加载器(Bootstrap ClassLoader),是虚拟机自身的一部分,用来加载 Java_HOME/lib/目录中的,或者被 -Xbootclasspath 参数所指定的路径中并且被虚拟机识别的类库;

  • 其他类加载器:

  • 扩展类加载器(Extension ClassLoader):负责加载\lib\ext 目录或 Java. ext. dirs 系统变量指定的路径中的所有类库;

  • 应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。


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


5、说一下类装载的执行过程?


类装载分为以下 5 个步骤:


  • 加载:根据查找路径找到相应的 class 文件然后导入;

  • 检查:检查加载的 class 文件的正确性;

  • 准备:给类中的静态变量分配内存空间;

  • 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址;

  • 初始化:对静态变量和静态代码块执行初始化工作。


6、怎么判断对象是否可以被回收?


一般有两种方法来判断:


  • 引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题;

  • 可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。


7、Java 中都有哪些引用类型?


  • 强引用:发生 gc 的时候不会被回收。

  • 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。

  • 弱引用:有用但不是必须的对象,在下一次 GC 时会被回收。

  • 虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。


8、说一下 JVM 有哪些垃圾回收算法?


  • 标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片。

  • 标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。

  • 复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。

  • 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法。


9、说一下 JVM 有哪些垃圾回收器?


  • Serial:最早的单线程串行垃圾回收器。

  • Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS 垃圾回收器的备选预案。

  • ParNew:是 Serial 的多线程版本。

  • Parallel 和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。

  • Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法。

  • CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。

  • G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项。


10、详细介绍一下 CMS 垃圾回收器?


CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候会产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。


11、新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?


  • 新生代回收器:Serial、ParNew、Parallel Scavenge

  • 老年代回收器:Serial Old、Parallel Old、CMS

  • 整堆回收器:G1


新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。


12、简述分代垃圾回收器是怎么工作的?


分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。


新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:


  • 把 Eden + From Survivor 存活的对象放入 To Survivor 区;

  • 清空 Eden 和 From Survivor 分区;

  • From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。


每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。


老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。


13、说一下 JVM 调优的工具?


JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具。


  • jconsole:用于对 JVM 中的内存、线程和类等进行监控;

  • jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等。


14、常用的 JVM 调优的参数都有哪些?


XX 比 X 的稳定性更差,并且版本更新不会进行通知和说明。


  • -Xms


s 为 strating,表示堆内存起始大小


  • -Xmx


x 为 max,表示最大的堆内存


(一般来说-Xms 和-Xmx 的设置为相同大小,因为当 heap 自动扩容时,会发生内存抖动,影响程序的稳定性)


  • -Xmn


n 为 new,表示新生代大小


(-Xss:规定了每个线程虚拟机栈(堆栈)的大小)


  • -XX:SurvivorRator=8


表示堆内存中新生代、老年代和永久代的比为 8:1:1


  • -XX:PretenureSizeThreshold=3145728


表示当创建(new)的对象大于 3M 的时候直接进入老年代


  • -XX:MaxTenuringThreshold=15


表示当对象的存活的年龄(minor gc 一次加 1)大于多少时,进入老年代


  • -XX:-DisableExplicirGC


表示是否(+表示是,-表示否)打开 GC 日志


15、你能保证 GC 执行吗?


不能,虽然你可以调用 System.gc() 或者 Runtime.gc(),但是没有办法保证 GC 的执行。


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


可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及 最大堆内存。


通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间。 Runtime.freeMemory() 方法返回剩余空间的字节数,Runtime.totalMemory() 方法总内存的字节数,Runtime.maxMemory() 返回最大内存的字节数。


17、Java 中堆和栈有什么区别?


JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局 部变量,而对象总是在堆上分配。


栈通常都比堆小,也不会在多个线程之间共享, 而堆被整个 JVM 的所有线程共享。

JVM 底层 与 GC(Garbage Collection)的面试题答案

1、64 位 JVM 中,int 的长度是多数?


Java 中,int 类型变量的长度是一个固定值,与平台无关,都是 32 位。意思就 是说,在 32 位 和 64 位 的 Java 虚拟机中,int 类型的长度是相同的。


2、Serial 与 Parallel GC 之间的不同之处?


Serial 与 Parallel 在 GC 执行的时候都会引起 stop-the-world。


它们之间主要 不同 serial 收集器是默认的复制收集器,执行 GC 的时候只有一个线程,而 parallel 收集器使用多个 GC 线程来执行。


3、32 位和 64 位的 JVM,int 类型变量的长度是多数?


32 位和 64 位的 JVM 中,int 类型变量的长度是相同的,都是 32 位或者 4 个字节。


4、Java 中 WeakReference 与 SoftReference 的区别?


虽然 WeakReference 与 SoftReference 都有利于提高 GC 和 内存的效率, 但是 WeakReference ,一旦失去最后一个强引用,就会被 GC 回收,而软引用 虽然不能阻止被回收,但是可以延迟到 JVM 内存不足的时候。


5、WeakHashMap 是怎么工作的?


WeakHashMap 的工作与正常的 HashMap 类似,但是使用弱引用作为 key, 意思就是当 key 对象没有任何引用时,key/value 将会被回收。


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


当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位增加到了 64 位,因此堆内存会突然增加,差不多要翻倍。


这也会对 CPU 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCompressedOops 选项,JVM 会使用 32 位的 OOP,而不是 64 位 的 OOP。


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


你可以检查某些系统属性如 sun.arch.data.model 或 os.arch 来获取该信息。


8、32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数?


理论上说上 32 位的 JVM 堆内存可以到达 2^32,即 4GB,但实际上会比这个 小很多。不同操作系统之间不同,如 Windows 系统大约 1.5 GB,Solaris 大约 3GB。


64 位 JVM 允许指定最大的堆内存,理论上可以达到 2^64,这是一个非 常大的数字,实际上你可以指定堆内存大小到 100GB。甚至有的 JVM,如 Azul, 堆内存到 1000G 都是可能的。


9、JRE、JDK、JVM 及 JIT 之间有什么不同?


JRE 代表 Java 运行时(Java run-time),是运行 Java 引用所必须的。JDK 代 表 Java 开发工具(Java development kit),是 Java 程序的开发工具,如 Java 编译器,它也包含 JRE。JVM 代表 Java 虚拟机(Java virtual machine),它 的责任是运行 Java 应用。


JIT 代表即时编译(Just In Time compilation),当 代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码,如,主 要的热点代码会被转换为本地代码,这样有利大幅度提高 Java 应用的性能。




这些题你答对了几道呢,正确率不高的同学也别沮丧,我整理了一些关于虚拟机的电子书资料,只要好好消化这些资料,再也不怕面试官问到这块的问题。



除了这些,其他热门技术的面试题我也一直有在整理,都可以免费分享给大家的



关注+转发+私信【608】就可以直接领取以上所有资料哦!

发布于: 2021 年 06 月 09 日阅读数: 17
用户头像

北游学Java

关注

进群1044279583分享学习经验和分享面试心得 2020.11.16 加入

我秃了,也变强了

评论

发布
暂无评论
24道几乎必问的JVM面试题,我只会7道,你能答出几道?