# 前言
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 与 P
arallel GC 之
间的不同之处?**
* **32位和64位的JVM,int类型变量的长度是多数?**
* **Java中WeakReference与SoftReference的区别?**
* **WeakHashMap是怎么工作的?**
* **JVM 选项-XX:+UseCom
pressedOops有什么作用? 为什么要使用?**
* **怎样通过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/目录中的,或者被 -X
bootclasspath 参数所指定的路径中并且被虚拟机识别的类库;
* 其他类加载器:
* 扩展类加载器(Extension ClassLoader):负责加载\lib\ext目录或Java. ext. d
irs系统变量指定的路径中的所有类库;
* 应用程序类加载器(Application ClassLoader)。负责加载
用户类路径(cla
sspath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有
自定义类加载器
默认就是用这个加载器。
双亲委派模型:如果
一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给
父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的
搜索范围中没找到所需的类)时,子加载器才会尝试去加载类。
**5、说一下类装载的执行过程?**
类装载分为以下 5 个步骤:
* 加载:根据查找路径找到相应的 class
文件然后导入;
* 检查:检查加载的 class
文件的正确性;
* 准备:给类中的静态变量分配内存空间;
* 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为
一个标示,而在直接引用直接指向内存中的地址;
* 初始化:对静态变量和静态
代码块执行初始化工作。
**6、怎么判断对象是否可以被回收?**
一般有两种
方法来判断:
* 引用计数器:为每个
对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有
一个缺点不能
解决循环引用的问题;
* 可达性分析:从 GC Roots 开始向下
搜索,
搜索所走过的路径称为引用链。当
一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。
**7、Java中都有哪些引用类型?**
* 强引用:发生 gc 的时候不会被回收。
* 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
*
弱引用:有用但不是必须的对象,在下一次GC时会被回收。
* 虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 Phant
omreference 实现虚引用,虚引用的用途是在 gc 时返回
一个通知。
**8、说一下JVM有哪些
垃圾回收算法?**
*
标记-清除算法:
标记无用对象,然后进行清除回收。缺点:效率不高,无法清除
垃圾碎片。
*
标记-整理算法:
标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存。
* 复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半。
* 分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用
标记整理算法。
**9、说一下JVM有哪些
垃圾回收器?**
* Serial:最早的单线程串行
垃圾回收器。
* Serial Old:Serial
垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS
垃圾回收器的备选预案。
* ParNew:是 Serial 的多线程版本。
* P
arallel 和 ParNew 收集器类似是多线程的,但 P
arallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量。
* P
arallel Old 是 P
arallel 老生代版本,P
arallel 使用的是复制的内存回收算法,P
arallel Old 使用的是
标记-整理的内存回收算法。
* CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统。
* G1:一种兼顾吞吐量和停顿时
间的 GC 实现,是 JDK 9 以后的
默认 GC 选项。
**10、详细介绍一下CMS
垃圾回收器?**
CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时
间的垃圾回收器。对于要求服务器响应速度的应用上,这种
垃圾回收器非常适合。在启动 JVM 的参数
加上“-XX:+UseCon
cmarkSweepGC”来指定使用 CMS
垃圾回收器。
CMS 使用的是
标记-清除的算法实现的,所以在 gc 的时候会产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行
垃圾清除,此时的
性能将会被降低。
**11、新生代
垃圾回收器和老生代
垃圾回收器都有哪些?有什么区别?**
* 新生代回收器:Serial、ParNew、P
arallel Scavenge
* 老年代回收器:Serial Old、P
arallel 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为st
rating,表示堆内存起始大小
* -Xmx
x为max,表示最大的堆内存
(一般来说-
xms和-Xmx的设置为相同大小,因为当heap
自动扩容时,会发生内存抖动,影响程序的稳定性)
* -Xmn
n为new,表示新生代大小
(-Xss:规定了每个线程虚拟机栈(堆栈)的大小)
* -XX:SurvivorRator=8
表示堆内存中新生代、老年代和永久代的比为8:1:1
* -XX:PretenureSizeThreshold=3145728
表示当创建(new)的对象大于3M的时候直接进入老年代
* -XX:MaxTenuringThreshold=15
表示当对象的存活的年龄(mi
nor gc一次加1)大于多少时,进入老年代
* -XX:-
disableExplicirGC
表示是否(+表示是,-表示否)打开GC日志
**15、你能保证GC执行吗?**
不能,虽然你可以
调用 Sy
stem.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与P
arallel GC之
间的不同之处?**
Serial 与 P
arallel 在 GC 执行的时候都会引起 stop-the-world。
它们之间主要 不同 serial 收集器是
默认的复制收集器,执行 GC 的时候只有
一个线程,而 p
arallel 收集器使用多个 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:+UseCom
pressedOops有什么作用? 为什么要使用?**
当你将你的应用从 32 位的 JVM 迁移到 64 位的 JVM 时,由于对象的指针从 32 位
增加到了 64 位,因此堆内存会突然
增加,差不多要翻倍。
这也会对
cpu 缓存(容量比内存小很多)的数据产生不利的影响。因为,迁移到 64 位的 JVM 主要动机在于可以指定最大堆大小,通过压缩 OOP 可以节省一定的内存。通过 -XX:+UseCom
pressedOops 选项,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】就可以直接领取以上所有资料哦!**
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。