jvm面试必看系列
更多更详细的面试资料点赞+关注,私信我获取
JVM加载流程和运行时数据区如下图所示:
运行时数据区
方法区
方法区
用于存储已经被加载的类信息、常量、静态变量、编译后的代码以及 运行时常量池
等。
堆
堆
主要存放一些数据,比如对象实例、数组等。
堆内存会划分为年轻代和老年代,年轻代又会分为Eden和Servivor区,Survivor也会分为FromPlace和ToPlace。
虚拟机栈
虚拟机栈
描述的是JVAV方法执行的内存模型。每个方法被执行的时候同时都会创建一个栈帧
,用于存储局部变量表
,操作数栈
,动态链接
,方法出口
等信息,不存在垃圾回收问题,只要线程结束,该栈就释放。
本地方法栈
和栈作用类似,但是本地方法栈执行的是native方法。
程序计数器
程序计数器
可以看做是当前线程所执行的行号指示器。
内存泄露和内存溢出
内存泄露的原因
- 对象是可达的(一直被引用)
- 对象不会被使用。
这些对象不会被GC所回收,但是却一直占用内存。
内存溢出的原因
- 内存泄露导致堆栈内存不断增大
- 大量的jar,class文件加载,装载类的空间不够
- 操作大量的对象导致堆内存空间用满
GC的方式
- Minor GC: 年轻代,频率高,速度快
- Major GC:老年代
- Full GC:整个堆(年轻代,老年代)
虚拟机堆的年轻代和年老代
- 当Eden空间满了之后,会触发一次Minor GC,GC之后还存活的对象将被复制到两个Survivor区域中的一个。假定该Servivor为From区,From区被填满之后,这个区域也要进行GC,GC之后存活的对象会复制到To区,From区清空,因此From和To区必有一区是空的。如此交换15次,最终如果还是存活,将存入老年代。
- 如果对象的大小大于Eden的二分之一会直接分配在老年代区。如果老年代也分配不下,会做一次老年代的major GC。
- 如果minor GC后,survivor仍然放不下,则放到老年代。
- 动态年龄判断。大于等于某个年龄段的对象超过了Servivor空间的一半,则直接进入老年代。
双亲委派模式
当一个类收到加载请求时,它不会先自己去尝试加载,而是委派给父类去完成。
作用:为了解决类载入过程中的安全性问题。
- 假设有一个开发者自己编写了一个名为
java.lang.Object
的类,想借此欺骗JVM。现在他要使用自定义ClassLoader
来加载自己编写的java.lang.Object
类。 - 然而幸运的是,双亲委托模型不会让他成功。因为JVM会优先在
BootstrapClassLoader
的路径下找到java.lang.Object
类,并载入它。
类的实例化顺序
- 父类静态成员和静态初始化块,按代码块中出现的顺序依次执行。
- 子类静态成员和静态初始化块,按代码块中出现的顺序依次执行。
- 父类实例成员和实例初始化块,按代码块中出现的顺序依次执行。
- 父类构造方法
- 子类实例成员和实例初始化块,按代码块出现的顺序依次执行。
- 子类构造方法。
JVM中一次完整的GC流程是怎样的?
YGC和FGC表示什么?
- YGC(Young GC): 对新生代堆进行GC。频率比较高,因为大部分对象的存活寿命较短,在新生代里被回收,性能耗费较小。
- FGC(Full GC): 全堆范围的GC。默认堆空间使用到达80%的时候回触发FGC、
JVM垃圾回收算法有哪些?
我们常用的垃圾回收器一般采用分代收集算法。
标记-清除算法
算法分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有标记的对象。
标记压缩算法
首先先标记需要回收的对象,然后让所有存活的对象都向一端移动,最终清理掉端边界以外的内存。
复制算法
将可用内存划分为大小相等的两块,每次用掉其中的一块。当着一块的内存用完了,就将还存活的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉。
分代收集算法
将JAVA堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的收集算法。
常见的垃圾收集器有哪些?
CMS收集器
CMS收集器
,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。- CMS收集器需要消耗额外的CPU和内存资源,在CPU和内存资源紧张时,会加重系统负担,
- CMS无法处理浮动垃圾,CMS的
标记-清除
算法,会导致大量的空间碎片的产生。
G1收集器
G1(Garbage-First)是一款面向服务端的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器,具备极高概率满足GC停顿的同时,还具备高吞吐量性能特征。
Serial收集器
Serial
收集器,是最古老,最稳定以及效率高的串行收集器。- 只使用一个线程去回收,可能产生较长的停顿。