jvm - GC垃圾回收器(一)年轻代+老年代

时间:2024-04-10 16:48:17

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

四种主要的垃圾回收器:
    * Serial(串行垃圾回收器):后台只有一个线程负责垃圾回收,当它回收时,会暂停所有用户线程,所以不适合服务器环境。(一个人打扫,其他客人都得等着)
    * Parallel(并行垃圾回收器):后台有多个线程负责垃圾回收,当它们回收时,同样暂停所有用户线程,适用于科学计算/大数据处理等若交互场景。(一堆人打扫,客人都得等着)
    * CMS(并发标记清除,简称 并发垃圾回收器):(它其实分4步,有两步其实还是会暂停一下,但效率已经高很多了)(边吃边打扫)

jvm - GC垃圾回收器(一)年轻代+老年代


    * G1(Garbage first回收器):jdk1.8推出,是jdk1.9的默认垃圾回收器,jdk11出了个ZGC(更吊);

G1将堆内存分割成不同的区域,然后并发地对其进行垃圾回收。

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

 

jvm - GC垃圾回收器(一)年轻代+老年代

查看默认的垃圾回收器是哪个:
java -XX:+PrintCommandLineFlags -version     (红字显示是并行垃圾回收器)

jvm - GC垃圾回收器(一)年轻代+老年代

如果想改成第一种串行垃圾回收器,则 -XX:+UseSerialGC ,使用该命令后(在IDEA中设置),查看:

jvm - GC垃圾回收器(一)年轻代+老年代

而查看JVM参数初始设定的命令是: java -XX:+PrintFlagsInitial

 

之前说垃圾回收器有4种,但是从源码中看,其实默认的垃圾回收器共6种:(其实还有一种叫UseSerialOldGC,基本废除淘汰了,加上它,就是所谓的7大垃圾回收器)

 

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

Serial Copying = UseSerialGC
Parallel Scavenge = UseParallelGC    1.8以及之前默认UseParallelGC,1.9默认使用G1.
ParNew = UseParNewGC

Serial MSC(Serial Old) = UseSerialOld    已废除
Parallel Compacting(Parallel Old) = UseParallelOld
CMS = UseConcMarkSweepGC

部分参数的对照翻译表:
(这些参数显示在PrintGCDetails里面,说明新生代和老年代用的是什么垃圾收集器)

jvm - GC垃圾回收器(一)年轻代+老年代

叉表示从jdk1.8开始,新生代使用的垃圾回收器对应的在养老区的垃圾回收器不推荐使用。(不推荐不代表不使用,事实上从左往右数第二个叉在默认情况下并未起作用,见二(自己解释一下:原来默认是ParNew+Serial Old,在jdk1.8不推荐了,但是默认还是ParNew+Serial Old))
(如在新生代使用Serial垃圾回收器,则在养老区不能使用CMS垃圾回收器,而只能使用SerialOld垃圾回收器)

jvm - GC垃圾回收器(一)年轻代+老年代

A指向B,表示:当启用A,会跟着配套启用B使用。
在之前,年轻代的Serial、Parallel Scavenge、ParNew都默认使用Serial Old。
在jdk1.8开始,不推荐Parallel Scavenge和ParNew和Serial Old配套使用了,而是让Parallel Scavenge和Parallel Old相互**,让CMS**ParNew(Serial Old作为CMS的后备老年代垃圾回收器)。(Serial还是和Serial Old配合,这点不变)

 

一、串行GC(Serial)(Serial Copying)

适合单cpu服务器

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

即jvm客户端默认还是使用Serial作为垃圾回收器、适合于单CPU环境

 

jvm - GC垃圾回收器(一)年轻代+老年代

因为现在计算机都不止一个CPU,所以Serial垃圾回收器基本已经废除了;
因为只有一个线程负责GC,而又只有一个CPU,所以不涉及在多个GC线程之间切换,所以在一个CPU的情况下,Serial垃圾回收器可以获得最高的单线程垃圾收集效率。

 

二、并行GC(ParNew)

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

ParNew是很多JVM在新生代下的默认垃圾回收器: 难道不是Parallel吗???是的!所以这里不用在意,当它写错了

 

三、并行回收GC(Parallel)(Parallel Scavenge) 默认的那个

(俗称:吞吐量优先收集器)
年轻代默认使用
和Parallel Old相互**

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

使用上面任意一个后,老年代默认开启使用Parallel Old(因为Parallel和Parallel Old相互**)

jvm - GC垃圾回收器(一)年轻代+老年代

读完还是没懂,ParNew和Parallel的区别是什么:
Parallel它关注的重点是:

jvm - GC垃圾回收器(一)年轻代+老年代

所以,为了使用这个Parallel垃圾回收器,在IDEA中配置 -XX:UseParallelGC 或 -XX:UseParallelOldGC即可(它俩可以相互**),因为:(见红色方框)

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

 

四、并行GC(Parallel Old)(Parallel MSC)

它和Parallel可以相互**

jvm - GC垃圾回收器(一)年轻代+老年代

Parallel Old正是为了在老年代提供同样吞吐量优先的垃圾回收器:因为年轻代中Parallel Scavenge和ParaNew相比的优点就是提供了更高吞吐量,但只是提供了年轻代更高的吞吐量,而无法保证整体的高吞吐量。所以从jdk1.8开始,不再将Parallel Scavenge与Serial Old绑定,而是将Parallel Scavenge与Parallel Old绑定,以保证整体的高吞吐量。

只使用3,也可以开启Parallel Old

jvm - GC垃圾回收器(一)年轻代+老年代

 

五、并发标记清除GC(CMS)

(其他的老年代收集器都使用标记整理算法,所以这里准备讲的垃圾回收器CMS的缺点很明显:有内存碎片)
用在养老区;
标记清除是GC的第三种算法,缺点是遍历两次、有内存碎片;
互联网公司一般都用CMS垃圾回收器;

CMS有4步:

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

三者合作:

jvm - GC垃圾回收器(一)年轻代+老年代

CMS有4步:
7步的详见:https://www.codercto.com/a/45937.html

jvm - GC垃圾回收器(一)年轻代+老年代

1、初始标记(STW)
从垃圾回收的“根对象”开始,且只扫描直接与“根对象”直接关联的对象,并做标记,在此期间,其他线程都会停止。耗时短。

2、并发标记,和用户线程一起(并发)
从GC Root 开始对堆中对象进行可达性分析,找出存活的对象。

3、重新标记(STW)

jvm - GC垃圾回收器(一)年轻代+老年代

4、并发清除,和用户线程一起(并发)


CMS总结:

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代

在运行结果中也能看到4步:

jvm - GC垃圾回收器(一)年轻代+老年代

优点:
并发收集,停顿低
缺点:
并发执行,对CPU资源的压力大;

jvm - GC垃圾回收器(一)年轻代+老年代

采用的标记清除算法会导致大量内存碎片。

jvm - GC垃圾回收器(一)年轻代+老年代

代码演示:
-XX:+UseConcMarkSweepGC

jvm - GC垃圾回收器(一)年轻代+老年代

结果:
明明指定了一个垃圾回收器CMS,但是却不光显示了老年代用CMS,还显示了年轻代:使用ParNew(原因:它们是配套使用的,甚至老年代还有一个备选方案)

jvm - GC垃圾回收器(一)年轻代+老年代

 

说穿了,配-XX:+UseConcMarkSweepGC   (CMS)
最后实现的就是:

jvm - GC垃圾回收器(一)年轻代+老年代

 

六、串行GC(Serial Old)(Serial MSC)

其实就是年轻代的串行搬到了老年代而已
jvm - GC垃圾回收器(一)年轻代+老年代

 

jvm - GC垃圾回收器(一)年轻代+老年代

结果:

jvm - GC垃圾回收器(一)年轻代+老年代

 

6中垃圾回收器(G1还没讲)总结:

jvm - GC垃圾回收器(一)年轻代+老年代

一些新老代垃圾回收器的经典组合:

jvm - GC垃圾回收器(一)年轻代+老年代

jvm - GC垃圾回收器(一)年轻代+老年代