JVM垃圾收集器!
JVM垃圾收集器!
月伴飞鱼基本概念
串行
Serial
收集:
- 所有用户线程停止,单条GC线程回收堆的情况被称为串行回收。
并行
Parallel
收集:
- 所有用户线程停止,多条GC线程回收堆的情况(需多核CPU支持)。
独占
Monopoly
执行:
- GC工作时,GC线程会抢占所有资源执行,整个应用程序会被停止。
并发
Concurrent
执行:
- 用户线程和GC线程同时(交替)执行的情况,不会停下某类线程。
吞吐量:
指CPU用于执行用户代码的时间与CPU总耗时的比值,计算公式为:
- 吞吐量 = 用户代码执行总时长 /(用户代码执行总时长 + 垃圾回收总时长)。
如JVM在线上执行了
100min
,其中执行用户代码花费了99min
,垃圾回收总用时1min
。
- 那么吞吐量则为
99min/(99min+1min)=99%
。
写屏障:
指在赋值操作前后加入一些逻辑处理(类似于SpringAOP面向切面前后置处理的思想)。
GC组合方案:
追求低延迟,用户交互度较为频繁:采用:
ParNew + CMS
。追求高吞吐,后台计算工作较多:采用:
Parallel Scavenge + Parallel Old
。
Serial收集器
单线程的GC收集器,被称为串行收集器。
该收集器在发生GC时,会产生STW,也就是会停止所有用户线程。
由于会停止其他用户线程,所以在执行GC时并不会出现线程间的切换。
在单颗
CPU
的机器上,它的清理效率非常高。一般来说,采用
Client
模式运行的JVM,选取该款收集器作为内嵌GC是个不错的选择。
ParNew收集器(多线程)
Serial
收集器的多线程版本,是作用于新生代区域的收集器。
- 在整个实现上,除开GC收集阶段会使用多条线程回收外,其他实现几乎与
Serial
收集器大致相同。该款GC收集器因为采用了多线程,所以需要多核CPU的支持。
该收集器会根据CPU核数,开启不同的GC线程数,从而达到最优的垃圾回收效果(也可通过
-XX:ParallelGCThreads
参数指定)。
- 若是单核的机器上运行时,其效率可能不如
Serial
。- 如果是以
Server
模式运行的程序,而老年代又采用了CMS
收集器,那么新生代搭配ParNew
是个不错的选择。
Parallel Scavenge收集器(多线程)
一款作用于新生代的多线程GC收集器,但与
ParNew
收集器不同的是:
ParNew
通过控制GC线程数量来缩短程序暂停时间,更关心程序的响应时间。Parallel Scavenge
更关心的是程序运行的吞吐量,更注重一段时间内,用户代码执行时长与程序执行总时长的占比。
PS
收集器可以通过-XX:MaxGCPauseMillis
与-XX:GCTimeRatio
参数精准控制GC发生时的时间以及吞吐量占比。
PS
收集器还可以通过开启-XX:+UseAdaptiveSizePolicy
参数,让JVM启动自适应的GC调节策略。开启该参数后,JVM会根据当前系统的运行状态调整吞吐比与GC时间,从而确保能够提供最合适的停顿时间和吞吐量。
Serial Old(MSC)收集器(单线程)
Serial Old(MSC)
与Serial
收集器相同,同样是一款单线程串行回收的收集器。不同的是:
MSC
是一款作用于年老代空间的收集器,它采用标记-整理算法对年老代空间进行回收。同时,该款收集器也可作为
CMS
的备用收集器使用。
Parallel Old收集器(多线程)
Parallel Old
则是Parallel Scavenge
收集器的年老代版本,同样采用多线程进行并行收集,其内部采用标记-整理算法。与新生代的
PS
收集器相同的是:PO
同样追求的是吞吐量优先。
ShenandoahGC
JDK12推出了
ShenandoahGC
收集器,它与G1、ZGC
收集器一样,都是基于分区结构实现的一款收集器。和ZGC对比,相同的是:它们的停顿时间都不会受到堆空间大小的影响。
ZGC收集器
JDK11时推出垃圾回收器
ZGC
,是一款基于分区概念的内存布局GC器。
- 是真正意义上的不分代收集器,无论是从逻辑上,还是物理上都不再保留分代的概念。
ZGC
主要是超低延迟与吞吐量,在实现时,ZGC
也会在尽可能堆吞吐量影响不大的前提下。实现在任意堆内存大小下都可以把垃圾回收的停顿时间限制在
10ms
以内的低延迟。
引入ZGC的目的主要有如下四点:
奠定未来GC特性的基础。
为了支持超大级别堆空间(
TB
级别),最高支持16TB
。在最糟糕的情况下,对吞吐量的影响也不会降低超过15%。
GC触发产生的停顿时间不会偏差
10ms
。