1、什么时候发生gc?
(1)gc主要分为新生代gc和老年代gc,这两者有什么区别了?
- 新生代 GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC 非常频繁,回收速度一般也比较快。一般发生新生代gc都是因为新生代eden区域不够,如果发生了新生代gc后,剩余的存活对象年龄会加一,而且会存放到Survivor 空间,如果存活对象的内存大于Survivor 空间,则采用分配担保策略存放到老年代内存中。
- 老年代 GC(Major GC/Full GC):指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上。
(2)什么时候开始新生代gc,什么时候老年代gc?
对象优先在新生代 Eden 区中分配,如果 Eden 区没有足够的空间时,就会触发一次 Young GC 。
什么时候老年代gc
- 在执行 Young GC 之前,JVM 会进行空间分配担保——如果老年代的连续空间小于新生代对象的总大小(或历次晋升的平均大小),则触发一次 Full GC 。
- 大对象直接进入老年代,从年轻代晋升上来的老对象,尝试在老年代分配内存时,但是老年代内存空间不够。
- 显式调用
System.gc()
方法时。
(3)老年代,新生代存放什么?
java创建一个对象基本上都是存放在新生代中,当新生代满了以后就会发生MinorGC ,当存活下来的对象年龄大于15就放入老年代中,当然这不是一成不变了,可以通过-XX:MaxTenuringThreshold修改,同时如果survivor空间有一半以上同龄的对象,则将该部分对象存放到老年代。
老年代还存放大对象,例如数组和字符串,另一个存放的就是长期存活的对象。
2、gc主要的回收那块区域?
(1)主要回收的是堆内存的对象的分配与回收和方法区中存放的类信息和常量等数据。
(2)如何判断一个对象无用或死亡?
堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断那些对象已经死亡(即不能再被任何途径使用的对象)。
一有两种方法:可达性分析和计数法。而jvm采用前者作为判断条件。可达性分析就是从一个GcRoot为根节点,依次往下搜索,遍历整个节点,经过的路径被称为引用链,如果一个对象没有任何的引用链能够与gcRoot联系,那么这个对象就是无用的,可以收回。
那么GcRoot可以是哪些了?
1 、 虚拟机栈(栈帧中的本地变量表)中引用的对象。
2、 本地方法栈中JNI(即一般说的native方法)引用的对象。
3、 方法区中的静态变量和常量引用的对象。
(3)无用的类信息和无用的常量
无用的常量:如果常量池中的常量没有其他变量对其引用,则判定无用。
无用的类信息:从三个方面进行判断
1)如果该类的所有实例都被回收。
2)该类的ClassLoader都被回收。
3)外部没有任何的反射引用该类,同时java.lang.Class对象被回收了。
3、gc的算法是什么,如何回收的?
(1)标记-清除
(2)标记-整理
(3)复制
4、使用那些垃圾回收器?
(1)serial(串行) 收集器,这是一个单线程的垃圾回收器,每次执行的时候都停止其他线程。优点在于简单,快捷。新生代采用复制,老年代使用标记-整理。
(2)parNew收集器,这是一个多线程的垃圾回收器,跟serial基本上一样。
(3)cms收集器,是意义上的第一个并发垃圾回收器。
CMS(Concurrent Mark Sweep)收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
实现步骤:
- 初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
- 并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
- 重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
- 并发清除: 开启用户线程,同时 GC 线程开始对为标记的区域做清扫。
(4)G1垃圾回收器
G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征.
- 初始标记
- 并发标记
- 最终标记
- 筛选回收