经典的垃圾收集器
[jdk7,jdk11)
并行、并发
-
并行(Parallel) :指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
-
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器运行在另一个 CPU 上。
serial
它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束
- 新生代采用标记-复制算法,老年代采用标记-整理算法。
- 原理:GC时,要停掉应用程序线程。单线程。
- 优点:耗内存少,没有线程交互开销,jvm客户端模式下可以用。
parnew
- 新生代采用标记-复制算法,老年代采用标记-整理算法。
- 它是许多运行在 Server 模式下的虚拟机的首要选择,除了 Serial 收集器外,只有它能与 CMS 收集器(真正意义上的并发收集器,后面会介绍到)配合工作
parallel scavenge
它看上去几乎和 ParNew 都一样,parallel scavenge收集器关注点是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)
- 新生代采用标记-复制算法,老年代采用标记-整理算法。
- 可并行(用户线程暂停,多个回收线程工作)收集
- 吞吐量可以控制。吞吐量=用户代码时间/(用户代码时间+垃圾回收时间)
- 适合后台计算
- 可以自适应调节分代的大小
serial old
Serial 收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在 JDK1.5 以及以前的版本中与 Parallel Scavenge 收集器搭配使用,另一种用途是作为 CMS 收集器的后备方案。
- 单线程
- 标记整理
- 客户端模式
- 老年代
parallel old
Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器。
- 支持多线程并发收集
- 标记整理
- 老年代
- 场合:期望吞吐量高,但处理器资源少
CMS
垃圾收集线程与用户线程(基本上)同时工作
- 关注stw,注重用户体验
- 并发收集、低停顿
- 标记-清除
- 服务器端
- 标记清除
- 流程:
- 初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快 ;
- 并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
- 重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
- 并发清除: 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。
- 缺点:
5.1 对处理器资源敏感
回收线程正比于处理器数量,处理器数量多,导致垃圾回收线程多,程序吞吐量下降
5.2 浮动垃圾
并发清除阶段,还会产生垃圾。这说明要预留空间给用户程序。如果预留较少会触发full gc,导致并发失败。
5.3 内存碎片
garbage first(G1)
- G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征.
- 改变:回收不是针对某个代,或堆的fullgc。而是哪里垃圾多回收哪里,可以达到局部回收。
- 基于region的堆内存布局:
堆分为多个region,每个region可以是新生代或老年代。垃圾收集器针对不同的region。 - humongous区:存大对象。
- 回收单元:region
- 可预测的停顿时间:m时间内,n时间内是回收时间。
回收的收益有个优先级列表。用户可以设置期望停顿时间100-300ms。
G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region(这也就是它的名字 Garbage-First 的由来) 。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。 - 存在问题:
7.1 每个region有记忆集,双向的卡表,记录新生代<–>老年代的引用关系,占用不少堆内存。
7.2 对于浮动垃圾,使用原始快照方法satb。 - 设计思路变了,不是清除所有垃圾,只要内存分配速率小于垃圾回收速率即可。
- 算法:整体标记整理,局部region是标记复制。不会有内存碎片。
- 回收过程:
暂时不计算用户线程执行过程中的动作(如何使用写屏障维护记忆集的操作)
10.1 初始标记:
TAMS指针:region中一部分空间划分出来,用于并发回收时新对象的分配。新分配的对象地址都要在tams指针以上。
标记gcroot,更新tams指针。
10.2并发标记
扫描对象图,处理satb
10.3最终标记
处理satb
10.4筛选回收
更新region的统计数据(回收价值)。
标记复制算法
ZGC 收集器
与 CMS 中的 ParNew 和 G1 类似,ZGC 也采用标记-复制算法,不过 ZGC 对该算法做了重大改进。
在 ZGC 中出现 Stop The World 的情况会更少!