Java:Java虚拟机的基本面试题
虚拟机描述了程序运行时的各种内在情况,在大型项目中排查问题还是蛮重要的。现在关于虚拟机这块儿,真正想招初级Java的中小型公司,反而不会问你这些,他们会问你Java基础(真的是要注重基础,别整什么分布式微服务,高并发优化啥的,把基础答好就行),一些常见的方法,集合类,sql,外加一些简单的算法题,排序居多,把树基本的看看也行。回答的差不多的就要了,要是能说几句内存划分和垃圾回收机制,简直加分了。不招初级java的,反而会问上你一些关于虚拟机的问题,但是问的又很基础。大公司的话,虚拟机的问题一定会问,而且会问的比较深入,要结合自己的调优经验来回答。总而言之,不管你几年经验,一个靠谱的公司,关于虚拟机是必问了。
回顾下虚拟机的基本知识点,比较基础,供参考
=============================================
1:关于jvm,可以理解为专门运行Java程序的一个容器,一个系统。要知道我们写的Java源文件是由编译器编译成字节码文件,接着由虚拟机中的解释器编译成机器码文件,才能被系统识别。正是由于虚拟机的存在,实现了Java跨平台。
2:jvm内存区域划分
方法区(永久代):存放被加载的类信息,常量,静态变量等,反正存放编译后的信息。 线程共享
堆:运行时数据区,存放变量,数组等等。是gc进行垃圾回收的主要区域。 线程共享
程序计数器:每个线程都有自己的独立计数器,是当前线程的字节码文件的行号指示器。如果线程正在执行native方法,计数器为空。线程私有
虚拟机栈:Java方法在执行的时候会创建一个栈帧,用于存放变量表,操作数栈,动态连接,方法出口等信息。一个Java方法调用完成,就是栈帧在虚拟机栈中入栈到出栈的一个过程。线程私有
本地方法栈:存放本地方法。线程私有
直接内存区域,不受jvm管理
注意:Java1.8中方法区(永久代)被移除,取之而来的叫“元数据区”,存放于本地内存,好处是读数据更快了。
3:堆从gc角度的细分,
新生代(eden,Servivor from, servivor to)与老年代
eden:新对象的出生地,如果对象太大,则直接分配到老年代。当Eden区内存不够,触发gc机制。
Servivor from:上一次gc的幸存者。servivor to:保留1次gc过程中的幸存者
gc回收过程:采用复制算法,过程是复制-清空-互换。首先将Eden,Servivorfrom中的 对象复制到Servivorto区域,年龄+1.如果对象年龄到了,或者是Servivorto区域位置不够了,则放到老年代。接着清除掉Eden,Servivorfrom中的对象,最后from和to区互换,原来的to区域成为下次gc的from区域。
老年代,存放比较大或者年龄较大的对象,老年代比较稳定,gc不会频繁执行,采取标记清除算法。
4:确定对象是否为垃圾的两种方式
引用计数器:一个对象如果不是垃圾,说明它肯定会被引用,计数器不为零,如果计数器为零,说明不太可能会被用到,即成了垃圾可回收对象。这个方法的缺点在于存在这么一种情况,两个对象互相引用,除此之外没有其它的引用,本质上是已经没什么用的对象了,但是由于互相引用的关系,计数器不为零,迟迟不能回收。
可达性分析:通过gc roots对象作为根节点,进行搜索,如果gcroots和任意一个对象之前都是不可达的,则称该对象是不可达的, 不可达对象至少经过两次标记后,则将进行回收。
5:垃圾回收算法
标记清除,复制,标记整理。不做详细介绍。
6:四种引用
强引用,软引用,弱引用,虚引用,不做详细介绍,具体概念看书。
7:分代收集算法
根据每个代的特点选择合适的算法:新时代,复制清空互换。老年代,标记清除或者标记整理。
8:分区收集算法
将堆内存划分为若干个连续的小区间,每个区间独立使用,独立回收,好处是可控制回收小区间的数量,合理回收,减少gc产生的停顿时间。
9:常见gc收集器
Serial,单线程,复制算法
ParNew,多线程,复制算法
Parallel Scavenge 多线程,复制算法。
Serial old ,单线程,标记整理
Parallel old 多线程,标记整理
cms,多线程,标记清除
G1:目前最好的收集器,采用标记整理,不产生内存碎片。 精准的控制停顿时间,不牺牲吞吐量的前提下, 实现低停顿回收。
10:类加载机制流程
加载---验证---准备---解析---初始化---使用---卸载
加载:内存中生成一个代表这个类的对象,作为方法区这个类各个数据的入口。
验证:验证字节码文件中的信息是否符合jvm规范。
准备:在方法区中分配这些变量所使用的内存空间。
解析:指虚拟机将常量池中的符号引用替换为直接引用的过程。
初始化:开始执行Java类中的代码。
11:几种不会引起类初始化的情况
1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
2. 定义对象数组,不会触发该类的初始化。
3. 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触 发定义常量所在的类。
4. 通过类名获取Class对象,不会触发类的初始化。
5. 通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初 始化,其实这个参数是告诉虚拟机,是否要对类进行初始 化。
6. 通过ClassLoader默认的loadClass方法,也不会触发初始化动作。
12:双亲委派模型概念
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父 类去完成,每一个层次类加载器都是如
此,因此所有的加载请求都应该传送到启动类加载其中, 只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需
加载的 Class),子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载 器加载这个类,最终都是委托给顶层的启
动类加载器进行加载,这样就保证了使用不同的类加载 器最终得到的都是同样一个Object对象。
13:虚拟机常见工具,作为大致了解,面试可能会问到
JConsole: java 监视与管理控制台
visualVM: 多合一故障处理该工具
jps: 虚拟机进程状况工具
jstat: 虚拟机统计信息监视工具
Jinfo java配置信息工具
jmap java 内存映像工具
jstack 堆栈跟踪工具
14:虚拟机常见参数
-Xmx 堆的大小上限
-Xms 堆区内存初始内存分配的大小
-XX:MaxPermSize 永久代上限
-XX:SurvivorRatio Eden与Survivor区的比例
-XX:PretenureSizeThreshold 晋升老年代对象大小
-XX:NewRatio 新生代(Eden+2S)和老年代的比值,4表示1:4
这个有很多,网上都可以找得到。、
===========================================
基本知识点就这些了,具体细节请看书,如果面试官问的不深入,我觉得这些基本包含了必问的点吧