1.如何判断对象是否死亡?
引用计数法
对象中加一个引用计数器,有地方引用它,计数器加1;引用失效,计数器减1;计数器为0的对象就是不能在被使用了。虽然实现简单,效率高,但是难解决对象之间相互循环引用的问题,所以不被JVM采用可达性分析算法
通过一个叫做GC Roots
的对象作为起点,从这个节点向下搜索,节点走过的路径成为引用链,当一个对象到GC Roots没有引用链的话,那么说明该对象要被回收了。
例如Object6~Object10
之间虽有引用关系,但是不能到达GC Roots,所以,它们就是需要被回收的对象。对象可以被回收,但是不一定就代表一定会回收。
2.介绍强引用,软引用,弱引用,虚引用
上述四种引用,引用强度逐渐减弱
- 强引用
就像是我们的生活必需品,垃圾回收器绝不会回收它。就算JVM抛错,也不会随意回收强引用对象 - 软引用
可有可无的生活用品。内存空间足够,垃圾回收器不会回收它;如果不足了,就回收。 - 弱引用
类似可有可无生活用品。 - 虚引用
形同虚设。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
总结:使用软引用较多,因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统运行安全,防止内存溢出等问题产生
3.如何判断一个常量是废弃常量?
如果没有任何对象引用的话,那么就是废弃常量
4.如何判断一个类是无用的类?
满足下面三个条件才判定是无用的类:
- Java 堆中不存在该类的任何实例。(该类所有的实例都已经被回收)
- 加载该类的 ClassLoader 已经被回收
- 无法在任何地方通过反射访问该类的方法
5.垃圾收集有哪些算法,各自特点?
-
标记-清除算法
分为标记,清除阶段。先标记不需要回收的对象,标记完成后,统一回收掉所有没被标记的对象。
存在问题:1. 效率问题;2. 空间问题(会产生大量不连续的碎片) -
标记-复制算法
意义:为了解决效率问题
思想:将内存分为大小相同的两块,每次只使用其中一块。这一块使用完后,标记存活的对象复制到另一块去,然后把使用的空间全部清理。
图解:
但依然存在下面这些问题:
○ 可用内存变小:可用内存缩小为原来的一半。
○ 不适合老年代:如果存活对象数量比较大,复制性能会变得很差 -
标记-整理算法
思想:先标记不需要回收的对象,然后将这些存活对象向一端移动,最后直接清理掉边界以外的内存
图解:
-
分代收集算法(当前虚拟机采用的算法)
思想:根据对象存活周期将内存分为几块。一般将Java堆分为新生代和老年代,然后根据各个代的情况选择合适的回收算法
举例:新生代会有大量对象死去,可以选择标记-复制
算法。老年代对象存活几率高,没有额外的空间对它进行分配担保,所以必须选择标记-清除
或者标记-整理
算法
6.垃圾收集器
如果说垃圾收集算法是方法论的话,那么垃圾收集器就是内存回收的具体实现
串行垃圾收集器
是指单线程进行垃圾回收,垃圾回收时只有一个线程在工作,并且 Java 应用中所有线程都要暂停(STW)
Serial 收集器:作用于新生代,采用复制算法
Serial Old 收集器:作用域老年代,标记整理算法
图示:
并行垃圾收集器
JDK8 默认使用此垃圾回收器
Parallel New 收集器:作用于新生代,采用复制算法
Parallel Old 收集器:作用于老年代,采用标记整理算法
图示:
CMS(并发)收集器
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法
。主要作用在老年代
分为以下四个流程:
初始标记
: 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿。并发标记
: 进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿重新标记
: 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿。并发清除
: 不需要停顿。
图示:
下面解释初始标记、并发标记、重新标记、并发清理
如图所示,开始会初始标记
,初始标记就是标记和 GC Root 直接关联到的对象
,像 A 会被标记到,这个过程是阻塞的。接下来进行并发标记
,何为并发标记?就是会找到和 A 关联的对象
,例如 BCD 都会被标记到。那么为什么又要进行重新标记
?这是因为在代码运行过程中,有可能会出现新的引用,比如 A 对象引用了 X 对象,此时就不能回收了,此时就进行重新标记了。重新标记完成之后才会进行一个并发清理。
在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。
CMS 主要优点:并发收集、低停顿
。但是它有下面三个明显的缺点:对 CPU 资源敏感
;无法处理浮动垃圾
;它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生
。
G1收集器
应用在新生代和老年代中,JDK9 之后默认使用 G1 收集器
。
G1 收集器划分多个区域,每个区域都能充当 eden、survivor、old、humongous,humongous 是专为大对象准备的。G1 收集器采用的是标记复制算法,不会产生空间碎片。垃圾回收分为三个阶段:新生代回收,并发标记和混合收集
G1 收集器的运作大致分为以下几个步骤:初始标记、并发标记、最终标记、筛选回收