垃圾收集器
7款经典垃圾收集器与垃圾分代之间的关系
垃圾收集器的组合关系(更新到JDK14)
Serial 回收器 串行回收
-
在HotSpot虚拟机中 使用 -XX: UseSerialGC 可以指定年轻代和老年代都使用串行收集器
等价于 新生代使用Serial GC 且老年代使用Serial Old GC
-
Serial 收集器是一个新生代的垃圾收集器
-
Serial 收集器采用复制算法 串行回收和stop-the-world机制
-
Serial Old收集器也采用串行回收和stop-the-world机制 只不过内存回收算法采用标记-整理算法
-
现在已经不使用串行的了 串行限定在单核cpu才可以用 现在都不是单核的了
ParNew 回收器 并行回收
- ParNew 收集器可以看成是Serial收集器的多线程版本
- ParNew 只能处理新生代
- ParNew收集器在年轻代同样使用复制算法 stop-the-world机制 并行回收
- ParNew收集器适合运行在多cpu的场景 单cpu的场景不比Serial收集更高效
Parallel回收器 吞吐量优先
- Parallel使用 复制算法 stop-the-world机制 并行回收
- 与Parnew相比 Paralell的目标是达到一个可控制的吞吐量
- 在JDK1.6 时提供了Parallel Old收集器 用来替代Serial Old收集器
- Parallel Old收集器采用标记-压缩 算法 stop-the-world机制 并行回收
- 在JDK8 中默认是此垃圾收集器
- 由于高吞吐量的原因适合运行后台运算 科学计算的任务
CMS回收器 低延迟
- JDK1.5时 HotSpot推出了CMS 这款收集器是第一款真正意义上的并发收集器 他第一次实现了让垃圾收集线程和用户线程同时工作
- CMS的关注点是低时延这就更适合于用户交互的程序 有良好的响应速度
- CMS垃圾收集算法采用标记—清除算法 并且也会stop the world
-
初始标记 标记出GC Roots能直接关联到的对象 由于直接关联的对象较小 所以这个速度很快
这里会有stw的发生
-
并发标记 从GC Roots的直接关联对象遍历整个对象图的过程 这个过程耗时较长 但是不用停顿用户线程 可以和垃圾回收线程一起并发运行
-
重新标记 修正并发标记期间 因为用户线程运作导致的产生变动的那一部分对象的标记记录
-
并发清除 清除已经死亡的对象 与用户线程同时并发
-
特别注意
- CMS的优缺点
G1回收器 区域化分代式
-
官方给G1设定的目标是在延迟可控的情况下 获得尽可能高的吞吐量 担当起全功能收集器的重任与期望
-
为什么叫做G1呢?
G1跟踪各个Region里面的垃圾维护的价值大小 在后台维护一个优先列表 每次根据允许的收集时间 优先回收价值最大的Region
-
兼具并行与并发
并行性 G1回收期间 可以有多个GC线程同时工作 有效利用多核计算能力 此时用户线程STW
并发性 G1拥有与用户线程交替执行的能力 部分工作可以和用户线程同时执行
-
分代收集
虽然还保留新生代和老年代的概念 但新生代和老年代不是物理隔离的了 他们都是一部分Region的集合 通过Region的动态分配方式实现逻辑上的连续
-
空间整合
G1将内存划分成一个个的Region 内存的回收是以Region为基本单位的 Region之间是复制算法
但整体上可以看做是标记---- 压缩算法 避免了内存碎片的问题
- G1的垃圾回收过程主要包括以下3个环节
-
年轻代GC (Young GC)
当年轻代Eden用完的时候 开始年轻代的回收过程 在年轻代回收期间 G1 暂停所有用户线程 启动多线程执行年轻代的回收 从Eden区将存活对象移动到Survivor或者老年区 这是一个并行的独占式的回收过程 年轻代的垃圾回收只会回收Eden和Survivor区
-
老年代并发标记过程 (Concurrent Marking)
当堆内存使用到一定值 默认45% 开始老年代的并发标记过程
-
混合回收(Mixed GC)
G1的老年代回收器不需要整个老年代被回收 一次扫描只用回收一小部分老年代的Region就可了(只回收价值比较高的Region) 同时 这个老年代Region是和年轻代一起被回收的