尚硅谷2020最新版宋红康JVM教程学习笔记 八 垃圾回收器

点击查看合集

垃圾回收器分类

如果按照线程数分,可以分为串行垃圾回收器和并行垃圾回收器
在这里插入图片描述

串行回收器
同一时间段内只允许有一个CPU用于执行垃圾回收操作,此时工作线程被暂停,直至垃圾收集工作结束
适用场景:单CPU处理器或者较小的应用内存等硬件平台不是特别优越的场景,串行回收器的性能表现可以超过并行回收器和并发回收器。所以串行回收默认被应用在客户端的Client模式下的JVM中。(在并发能力比较强的CPU上,并行回收器产生的停顿时间要短于串行回收器)
并行垃圾回收器
和串行回收器享范,并行收集可以运用多个CPU同时执行垃圾回收,因此提升了应用的吞吐量,不过并行回收仍然与串行回收一样,采用独占式存在STW

如果按照工作模式来分,可以分为并发式垃圾回收器和独占式垃圾回收器

在这里插入图片描述

并发式垃圾回收
并发式垃圾回收器与应用程序线程交替工作,以尽可能减少应用程序的停顿时间
独占式垃圾回收器
独占式垃圾回收器一旦运行,就停止应用程序中的所有用户线程,直到垃圾回收过程完全结束。

按碎片处理方式分可以分为压缩式垃圾回收器和非压缩式垃圾回收器
压缩式垃圾回收器
压缩式垃圾回收器会在回收完成后,对存活对象进行压缩整理,消除回收后的碎片。
非压缩式垃圾回收器
非压缩式垃圾回收器会在回收完成后,不会对存活对象进行压缩整理

按工作内存区间分可以分为年轻代垃圾回收器和老年代垃圾回收器
年轻代垃圾回收器
应用于年轻代
老年代垃圾回收器
应用于老年代

评估GC的性能指标

吞吐量:运行用户代码的时间占总运行时间的比例
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间
内存占用:Java堆区所占的内存大小
垃圾收集开销:吞吐量得补数,垃圾收集所用时间与总运行时间的比例
收集频率:相对于应用程序的执行,收集操作发生的频率。
快速:一个对象从诞生到被回收所经历的时间
其中最重要的就是 吞吐量 暂停时间 内存占用

吞吐量和暂停时间

在这里插入图片描述
高吞吐量会让用户觉得程序运行很快。低暂停时间(低延迟)会让用户感觉体验更好(不卡顿)。但是高吞吐量和低暂停时间是一对相互竞争的目标。因为如果选择以吞吐量优先,那么必然需要降低内存回收得执行频率,但是这样会导致GC需要更长的时间来执行内存回收。
如果选择低延迟优先,那么为了将此每次执行垃圾回收的暂停时间,只能提高垃圾回收频率,但是这又引起了年轻代内存的缩减和导致程序吞吐量的下降。

在设计/使用GC算法时,我们必须确定我们的目标:一个GC算法只可能针对两个目标之一或者二者的折衷。
现在的标准:在最大吞吐量优先的情况下,尽量降低停顿时间

常见的垃圾回收器

在这里插入图片描述
在这里插入图片描述

Serial回收器与Serial Old回收器(串行回收)

HotSpot在Client模式下默认的新生代垃圾回收器,采用了复制算法、串行回收和STW机制的方式执行内存回收。

Serial Old收集器再Client模式下的默认老年代垃圾的垃圾回收器。
Serial Old收集器同样采用了串行回收和STW机制,支部会内存回收算法使用的是标记-整理算法
优点:简单高效(与其他收集器的单线程比),对于单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。
在这里插入图片描述

ParNew回收器(并行回收)

如果说Serial GC是年轻代中的单线程垃圾收集器,那么ParNew收集器则是Serial收集器的多线程版本。
ParNew收集器除了采用并行回收的方式执行内存回收外,它和Serial回收器之间几乎没有区别。
ParNew是很多JVM在Server模式下新生代的默认垃圾收集器
Par是parallel的缩写
在这里插入图片描述

Parallel Scavenge回收器和Parallel Old(吞吐量优先)

Parallel Scavenge回收器和ParNew收集器一样都是基于并行回收的并且都采用了复制算法,并行回收和STW机制。且同样作用于新生代
但是和ParNew收集器不同的地方是,Parallel Scavenge收集器的目标是达到一个可控制的吞吐量(吞吐量优先)。自适应调节策略也是Parallel Scavenge于ParNew的一个重要区别。
高吞吐量可以高效利用CPU,适合用于交互任务较少的服务器环境中。

Parallel Old收集器采用了标记-压缩算法,且也是基于并行回收和STW机制。用来在老年代进行垃圾回收。

Parallel Scavenge和Parallel Old垃圾回收器的组合是JDK8中的默认组合。在高吞吐量的服务器端很好用。

参数配置(Parallel Scavenge)

1.设置垃圾收集器的最大停顿时间(STW的时间)-XX:MaxGCPauseMillis
2.垃圾收集时间占总时间的比例-XX:GCTimeRation
3.手动指定年轻代使用Parallel并行收集器-XX:UseParallelGC(3和4开启一个另一个也会被激活)
4.手动指定老年代使用Parallel Old垃圾回收器-XX:UseParallelOldGC(3和4开启一个另一个也会被激活)
5.设置年轻代并行收集器的线程数:-XXParallelGCThreads(默认一般为CPU核心数)
6.设置开启自适应策略(默认开启)-XX:+UseAdaptiveSizePolicy

自适应策略(Parallel Scavenge)

-XX:+UseAdaptiveSizePolicy设置开启自适应策略(默认开启)
在这种模式下,年轻代的大小,Eden和Survivor的比例\晋升老年代的对象年龄等参数会自动被调整,已达到在堆大小,吞吐量和停顿时间之间的平衡点。
在游动调优比较困难的场合,可以直接使用这种自适应的方式,仅指定虚拟机的最大堆、目标的吞吐量(GCTimeRation)和停顿时间(MaxGCPauseMills)让虚拟机自己完成调优工作。

CMS回收器(低延迟)

CMS(Concurrent Mark Sweep)回收器。它真正意义上实现了并发收集器(垃圾收集线程与用户线程并发工作)是老年代的回收器。
CMS收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间。停顿时间越短(低延迟)就越适合与用户交互的程序,大大提高用户体验。
CMS采用标记清除算法并且也有STW机制。
CMS是老年代的收集器,不能与新生代的Parallel Scavenge配合工作
JDK14时被删除了
在这里插入图片描述
初始标记:这一步是STW的。标记处GC Roots能直接关联到的对象(耗时短且STW)
并发标记:从GC Roots的直接关联对象开始遍历整个对象图的过程(耗时长,不需要停顿用户线程)
重新标记:修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。
并发清除:清理删除掉标记阶段判断的已经死亡的对象,释放内存空间。由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

由于垃圾收集阶段用户线程没有中断,所以CMS回收过程中,还应该确保应用程序用户线程有足够的内存可用。因此当堆内存使用率达到一定的阈值时,便要开始进行回收,以确保应用程序在CMS工作过程中依然有足够的空间支持应用程序运行。如果CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”,这时虚拟机就会启动后备方案:临时启用Serial Old收集器来重新进行老年代的垃圾收集。

CMS采用标记-清除算法,这意味着会产生内存碎片。所以之后为新对象分配内存时,将不能使用指针碰撞技术,而只能够选择空闲列表。

为什么CMS不采用标记-整理算法?
因为CMS时,用户线程还在执行,因此不能改变对象的地址。

优点:
1.并发收集(某些阶段)
2.低延迟
缺点:
1.会产生内存碎片
2.CMS收集器对CPU资源非常敏感。并发阶段虽然不会导致用户停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量降低。
3.CMS收集器无法处理浮动垃圾。在并发标记阶段如果产生新的垃圾对象,CMS将无法对这些垃圾对象进行标记,最终会导致这些新产生的垃圾对象没有被及时回收。从而只能在下一次执行GC时释放这些之前未被回收的内存空间。

CMS收集器的参数设置

1.手动指定使用CMS-XX:+UseConcMarkSweepGC 开启该参数后会自动将-XX:+UseParNewGC打开。即ParNew+CMS+Serial Old组合使用
2.设置堆内存使用率的阈值: -XX:CMSlnitiatingOccupanyFraction (如果内存增长缓慢,可以把阈值设置的高一点)
3.用于指定Full GC后对内存空间进行整理,消除内存碎片.-XX:+UseCMSCompactAtFullCollection
4.设置执行多少次Full GC后对内存空间进行整理
5.设置CMS的线程数-XX:ParallelCMSThreads

G1回收器(区域分代化)

G1(Garbage First)回收器是为了适应不断扩大的内存和不断增加的处理器数量,进一步降低暂停时间,同时兼顾良好的吞吐量。
官方给G1设定的目标是在延迟可控的情况下获得尽可能高的吞吐量。
G1是一个并行回收器,它把堆分割为许多不相关的区域(Region)(物理上不连续)。使用不同的Region来表示Eden S0 S1 老年代。G1可以跟踪每个Region的垃圾堆积价值,在后台维护一个优先队列,每次根据允许的收集时间,优先回收价值最大的Region。由于这种方式的侧重点在于回收垃圾最大量的区域(Region),所以叫垃圾优先(G1/Garbage First)
G1是面向服务端应用的垃圾收集器,主要针对配备了多核CPU及大容量内存的机器,
G1中提供了三种垃圾回收模式:YoungGC Mixed GC Full GC
G1使用了全新的分区算法

优势

1.并行性和并发性:G1在回收期间,可以有多个GC线程同时工作。此时STW。G1拥有与应用程序交替执行的能力,部分工作可以和应用程序同时进行,因此,一般来说不会在整个回收阶段发生完全阻塞应用程序的情况
2.分代收集:不要求年轻代和老年代都是连续的,也不再要求固定大小和固定数量。它将堆空间分为若干个区域(Region),这些区域包含了逻辑上的年轻代和老年代。并且和其他GC不同的是,它同时兼顾老年代和年轻代。
在这里插入图片描述

3.空间整合:内存回收以Region为基本单位。Region之间是复制算法,但整体上实际可看作是标记-压缩算法。这两种算法都可以避免内存碎片的问题。
4.可预测的停顿时间模型:可以建立可预测的停顿时间模型,能让使用者明确指定再一个长度为M毫秒的时间片内,消耗在垃圾收集上的时间不得超过N毫秒。由于G1垃圾回收的最小单位是Region,缩小回收范围,因此对于全局停顿情况的发生也能得到较好的控制。G1还会维护一个优先队列,每次根据允许收集的时间,优先回收价值最大的Region。保证G1在有限时间内可以获取尽可能高的收集效率。

Remembered Set(记忆集)

为每个Region创建一个记忆集。如果要写入对象A,但是A还引用了别的Region的对象B,那么就在B所在的Region的记忆集中加入对象A的引用。这样之后要判断Region中的对象是否为垃圾时,只需要把记忆集中的引用也加入到GC Roots中。就可以避免全局扫描了。(分代回收器都采用记忆集的方式来避免全局扫描)

垃圾回收过程

1.年轻代GC(Young GC/minnor GC)
当Eden区内存用尽时,开始年轻代GC,它是一个并行的独占式收集器。暂停应用程序线程,启动多线程执行年轻代回收。然后从年轻代区间移动存活对象到Survivor区或者老年区。
2.老年代并发标记过程(Concurrent Marking)
当堆内存使用达到一定值(默认45%),开始老年代并发标记过程。标记完成后马上开始混合回收过程。
3.混合回收(Mixed GC)
G1回收器从老年代移动存活对象到空闲区间,这些空闲区间也就成为了老年代的一部分。G1的老年代回收器不需要整个老年代被回收,一次只需要扫描/回收一小部分老年代的Region就可以了。同时这个老年代Region是和年轻代一起被回收的。
4.如果需要,单线程,独占式,高强度的Full GC还是继续存在的。它针对GC的评估失败提供了一种失败保护机制,即强力回收。)

在这里插入图片描述

劣势

1.相较于CMS,G1无论是为了垃圾收集产生的内存占用还是程序运行时的额外执行负载都要比CMS高

从经验上来说,在小内存应用上CMS的表现大概率会优于G1,而G1在大内存应用上则发挥其优势。(平衡点在6-8GB之间)

G1参数设置

1.手动指定使用G1收集器执行内存回收任务-XX:+UseG1GC(JDK9后默认开启)
2.设置每个Region的大小。值是2的幂范围是1MB到32MB。目标是根据最小的Java堆大小划分出约2048个区域。默认是堆内存的1/2000.-XX:G1HeapRegionSize
3.设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到.)默认值是200ms.-XX:MaxGCPauseMillis
4.设置STW工作线程数(最多为8)-XX:ParallelGCThread
5.设置并发标记的线程数。(垃圾回收线程的1/4左右)-XX:ConcCGThreads
6.设置触发并发GC周期的Java堆占用率阈值。超过此值就出发GC默认为45.-XX:InitiatingHeapOccupancyPercent

Region

在这里插入图片描述
每个Region采用指针碰撞并且是TLAB(Thread Local allocation Buffer线程私有缓冲区)的。

G1回收过程

一:年轻代GC(回收年轻代)

JVM启动时,G1先准备好Eden区,当Eden空间耗尽时,G1会启动一次年轻代垃圾回收过程。(回收Eden区和Survivor区)
年轻代GC时会触发STW,G1创建回收集(需要被回收的内存分段的集合)。会收集包含年轻代Eden区和Survivorr区所有的内存分段。
在这里插入图片描述
1.初始标记阶段
2.根区域扫描
3.并发标记
4.再次标记
5.独占清理
6.并发清理阶段

二:并发标记过程(回收年轻代和部分老年代)

1.初始标记阶段
2.根区域扫描
3.并发标记
4.再次标记
5.独占清理
6.并发清理阶段

回收掉年轻代和100%为垃圾的老年代Region。剩下的存在部分垃圾的老年代Region会分8次(默认)在混合回收时回收。

三:混合回收(回收年轻代和部分老年代)

在这里插入图片描述

四:Full GC

G1的初衷就是为了避免Full GC的出现,因为Full GC使用单线程内存回收算法,性能很差。
发生Full GC的原因
1.Evacuation的时候没有足够的to-space来存放晋升的对象。
2.并发处理过储层完成之前空间被耗尽。

垃圾回收器总结

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_30033509/article/details/111085838
今日推荐