1.什么是JVM?java虚拟机包括什么?JVM内存模型?
答:JVM:java虚拟机 运用硬件或软件实现的虚拟的计算机
java虚拟机包括:堆栈,处理器,寄存器
程序计数器:当前线程所执行的字节码的型号指示器,用于记录正在执行的虚拟机字节指令地址,线程私有
java虚拟栈:存放基本数据类型,对象的引用,方法出口等,线程私有。
Native方法栈:和虚拟栈相似,只不过它服务于Native方法,线程私有。
java堆:java内存中最大的一块,所有对象实例,数据都存放在java堆,GC回收的地方,线程共享。
方法区:存放已被加载的类信息,常量,静态变量,即时编译器后的代码数据等。
2.什么情况下会发生栈内存溢出?
答题思路:首先描述栈的定义,再描述为什么会溢出,再说明一下相关的配置参数。
答:栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型。
1.如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常,方法递归调用产生这种结果。
2.如果JAVA虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展。或者在新建线程的时候没有足够的内存去创建对应的虚拟机栈,那么JAVA虚拟机将抛出一个OutOfMemory异常。(线程启动过多)
3.参数-Xss去调整JVM栈的大小
3.你知道哪几种垃圾收集器,重点讲下cms和G1
思路:记住典型的垃圾收集器,尤其是cms和G1,他们的原理和区别,涉及的垃圾回收算法。
(1)集中垃圾回收器:
Serial收集器: 单线程的收集器,收集垃圾时,必须stop the world,使用复制算法。
ParNew收集器: Serial收集器的多线程版本,也需要stop the world,复制算法。
Parallel Scavenge收集器: 新生代收集器,复制算法的收集器,并发的多线程收集器,目标是达到一个可控的吞 吐量。如果虚拟机总共运行100分钟,其中垃圾花掉1分钟,吞吐量就是99%。
Serial Old收集器: 是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。
Parallel Old收集器: 是Parallel Scavenge收集器的老年代版本,使用多线程,标记-整理算法。
CMS(Concurrent Mark Sweep) 收集器: 是一种以获得最短回收停顿时间为目标的收集器,标记清除算法,运作过程:初始标记,并发标记,重新标记,并发清除,收集结束会产生大量空间碎片。
G1收集器: 标记整理算法实现,运作流程主要包括以下:初始标记,并发标记,最终标记,筛选标记。不会产生空间碎片,可以精确地控制停顿。
(2)CMS收集器和G1收集器的区别:
CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用;
G1收集器收集范围是老年代和新生代,不需要结合其他收集器使用;
CMS收集器以最小的停顿时间为目标的收集器;
G1收集器可预测垃圾回收的停顿时间
CMS收集器是使用“标记-清除”算法进行的垃圾回收,容易产生内存碎片
G1收集器使用的是“标记-整理”算法,进行了空间整合,降低了内存空间碎片。
4.简单说说你了解的类加载器,可以打破双亲委派吗,怎么打破?
**思路:**先说明一下什么是类加载器,可以给面试官画个图,再说一下类加载器存在的意义,说一下双亲委派模型,最后阐述怎么打破双亲委派模型。
答:1)什么是类加载器?
类加载器就是根据指定权限定名称将class文件加载到JVM内存,转为class对象。
1.启动类加载器(Bootstrap ClassLoader):由C++语言实现(针对HotSpot),负责将存放在<JAVA_HOME>\bin目录或-Xbootclasspath参数指定的路径中的类库加载到内存中。
2.其他类加载器:由java语言实现,继承自抽象类ClassLoader。如:
扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\bin\ext目录或java.ext.dirs系统变量指定的路径中所有的类库。
应用程序类加载器(Application ClassLoader):负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器。
2)双亲委派模型工作过程:
如果一个类加载器收到类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时,(即ClassNotFoundException),子加载器才会尝试自己去加载。
3)为什么需要双亲委派模型?
如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,双亲委派模型防止内存中出现多份同样的字节码。
4)怎么打破双委派模型?
打破双亲委派机制不仅要继承ClassLoader类,还要重写loadClass和findClass方法。
5.说说你知道的几种主要的JVM参数
思路::可以说一下堆栈配置相关的,垃圾收集器相关的,还有一下辅助信息相关的。
a) 堆栈配置相关
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-XX:MaxPermSize=16m -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxTenuringThreshold=0
-Xmx3550m:最大堆大小为3550m
-Xms3550m:设置初始堆大小为3550m
-Xmn2g:设置年轻代大小为2g
-Xss128k:每个线程的堆栈大小为128k
-XX:MaxPermSize:设置持久代大小为16m
-XX:NewRation=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(出去持久代)
-XX:SurvivorRatio=4: 设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxTenuringThreshold=0: 设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。
b) 垃圾收集器相关
-XX:+UseParallelGC //选择垃圾收集器为并行收集器
-XX:ParallelGCThreads=20 //配置并行收集器的线程数
-XX:+UseConcMarkSweepGC // 设置年老代为并发收集
-XX:CMSFullGCsBeforeCompaction=5 //此值设置运行多少次GC以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:// 打开对年老代的压缩。可能会影响性能,但是可以消除碎片
6.怎样打出线程栈信息
**思路:**可以说一下jps,top ,jstack这几个命令,再配合一次排查线上问题进行解答
输入jps,获得进程号
top -Hp pid获取本进程中所有线程的CPU耗时性能
jstack pid 命令查看当前java进程的堆栈状态
或者 jstack -l > /tmp/output.txt 把堆栈信息打到一个txt文件。
可以使用fastthread 堆栈定位,fastthread.io/
7.强引用,软引用,弱引用,虚引用的区别?
思路: 先说一下四种引用的定义,可以结合代码讲一下,也可以扩展谈到ThreadLocalMap里弱引用用处。
1)强引用
我们平时new了一个对象就是强引用,例如 Object obj = new Object();即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。
2)软引用
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。
SoftReference<String> softRef=new SoftReference<String>(str); // 软引用
软引用在实际中有重要的应用,例如浏览器的后退按钮.
3)弱引用
具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
4) 虚引用
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。