1. Serial Colletor: -xx:+UseSerialGC.
它是一个单线程的,比较适合单核cpu的场景。
适用的场景:cpu核数比较少、内存空间比较少 100MB
新老年代之分:适用于新生代、老年代。灰色代表垃圾收集线程会暂停业务代码线程。后果就是对于客户端而言,响应变慢了。
现在所用的所有jvm垃圾收集,都有stop the world ,只是时间长短不一样。
为什么会停止业务代码的线程呢,就是希望业务代码不要执行,如果执行就会产生两个问题:
- 如果进行GC时,垃圾对象都会有一个标记,这个时候业务线程没有停下,业务线程可能会用到这个标记的垃圾对象,但这个对象是需要清理的。
- 归根到底,因为堆中的对象可能会发生变化(eden转移到servivor),不能让业务代码一直使用,如果一直使用,都是使用到旧地址。
2. Parallal GC XX:+UseParallelGC
既然单线程比较慢,那么就可以采用多线程(吞吐量优先),也有stw ,多线程收集、也有适用于新老年代的收集器。
3. Concurrent Mark Sweep(CMS) Collector
特点:更短的暂停响应时间,命令 -XX:UseConcMarkSweepGC。但需要注意的一点是,这个处理器只适合老年代。适用的是标记-清理算法,所以会有空间碎片的问题。
4. G-First
也是尽可能满足用户设置的停顿时间目标,并且很好解决了空间碎片问题。命令 -XX:UseG1GC.
吞吐量也会比较高。适用于新老年代。
5. ZGC(-XX:UseZGC)
可以是停顿时间达到几毫秒,但牺牲了一些吞吐量。
4. 垃圾收集器的分类
- 串行:只有一个垃圾收集线程执行 Serial
- 并行:有多个垃圾收集线程执行,业务代码不执行 Parallel GC 更加关注吞吐量
- 并发:垃圾收集线程和业务线程会同时执行 CMS G1 ZGC 更加关注停顿时间
吞吐量和停顿时间是评判一个垃圾收集器好坏的两个重要指标。
5. CMS
CMS是追求停顿时间的,目标域是老年代,也是一款老年代收集器,它会尝试最小化停顿时间,不会进行拷贝或压缩我们的对象,就意味着有空间碎片的问题。
如果你使用了CMS,那么新生代则会搭配一个ParNew。
通常情况下,一个新生代搭配一个老年代。当然如果这个GC可以用于老年代,也可以不用搭配。
采集器的四个阶段:
第一个阶段:初始标记
它会标记哪些可达的对象
第二个阶段并发标记:
第三阶段重新标记:
这三个标记都是为了确保对象的可达性
有一些阶段:垃圾收集线程和业务代码线程是共同执行的,所以停顿时间相对就少了。
针对CMS的不足,需要的解决方案:
- 停顿时间能不能再低一点
- 空间能否连续
针对这两种情况,于是有了G-First收集器
6. G1
满足低停顿的目标,又不会太牺牲吞吐量。停顿时间可以缩短到200ms以内、
还解决了空间碎片问题,从两个角度:
第一个,就是老年代算法,标记-整理
第二个,就是内存划分 region的概念
这个是C1的回收过程:
G1是将内存空间分成一个大小相同的regions,每一个都是连续的虚拟内存。这里的内存其实是对物理内存的映射。原先的堆内存空间是连续的,从young到old是按顺序的。而在G1中,也有完整的内存空间,但是新老年代不是连续的,不需要像以前一样在物理上连续,只需要在逻辑上连续。
前提:这些region的角色是可以转换的。
region的大小固定:区间:2^0 M- 2^5M 1-32M
如果超过region的50%称为大对象。
6.1. youngGC
youngGC前堆内存的状态
进行GC后,和前面的GC流程一样,会进入到survivor区,年龄大的会进入old区。在这个过程中依然会进入stop the world。
完成之后就变成这样:
小结:
- 这些region是物理上不连续的
- 当进行youngGC时,会进入stop the world
- 存活的对象会放到survivor、老年代
6.2. oldGC
也会有初始标记、并发标记、筛选回收这些步骤
其中初始标记、并发标记、最终标记、筛选标记都是扫描操作,找出不可达对象作为垃圾对象,并且开始清理,清理完成后,还有一个copy操作,主要为了下次进行。
Carvage-First
垃圾优先:这些对象region中有存活的对象,也有垃圾对象,那意思就是在回收的时候会有一个优先级。如何选择优先级呢:
先回收垃圾对象最多的region,因为存活率很少,就先回收。
回收这些region可以释放更多的空间,存活对象也比较少,说明可以更加快速、轻松的整理这些对象。
并且不是一个实时回收期,可以设置停顿时间,并且可以选择性回收。
垃圾回收的时机
- Sytem.gc
- Eden 空间不够用了
- old 空间不够用了
- MetaSapce 不够用了
Young GC = Minor GC
Old GC = Mahior GC
Full GC =Young + Old +Metaspace
Full GC =Young + Old
在虚拟机中一定要避免GC,这是第一个维度,优先级最高的
即使要发生GC,也尽可能发生在young区
如果避免不了发生major gc ,那jvm内部会有一个算法:每一次major之前,会先触发一次young gc
当发生old gc ,其实就等同发生full gc