预计阅读时间: 9分钟
我们在上一篇中已经详细的探究了关于JVM的垃圾回收的几种算法,从中我们知道了不同的算法有这不同的优缺点的,然而实际在Java的JVM的并不是单纯的使用其中的某一种算法来实现垃圾回收的,而是将不同的垃圾回收算法包装在不同的垃圾回收器当中,这样用户就可以根据自身的需求,有选择性的使用不同的垃圾回收器,以便让自己的java程序性能到达最佳。
垃圾回收器概述:垃圾收集器是垃圾回收算法(标记-清除算法、复制算法、标记-整理算法、分代收集算法等)的具体实现,不同商家、不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚拟机中的垃圾收集器。
在探究垃圾回收器之前我们先来回忆下之前探究过的关于JVM内存模型中的Java堆的知识,先来看一下Java堆的结构图如下:
java堆内存结构包括:新生代和老年代,其中新生代由一个伊甸区和2个幸存区组成,2个幸存区是大小相同,完全对称的,没有任何差别。我们把它们称为S0区和S1区,也可以称为from区和to区。
JVM的垃圾回收主要是针对以上堆空间的垃圾回收,当然其实也会针对元数据区(永久区)进行垃圾回收,在此我们主要针对堆内存空间的垃圾回收进行探究。
垃圾收集器组合:
下面我们介绍几种常见的垃圾回收器:
1、>>串行收集器:
(1)特点:
–它仅仅使用单线程进行垃圾回收
–它是独占式的垃圾回收
–进行垃圾回收时, Java应用程序中的线程都需要暂停(Stop-The-World)
–适合CPU等硬件不是很好的场合
–对新生代的回收使用复制算法,对老年代使用标记压缩算法,这也和之前介绍的垃圾回收算法优势是相合拍的
–是最古老最稳定的收集器,尽管它是串行回收,回收时间较长,但其稳定性是优于其他回收器的,综合来说是一个不错的选择。
(2)设置参数:
-XX:+UseSerialGC 指定新生使用新生代串行收集器和老年代串行收集器, 当以client模式运行时, 它是默认的垃圾收集器
串行回收器的执行流程如下所示:
2、>>并行回收器:
顾名思义,并行回收器就是使用多线程并行回收,不过这里需要注意的是,针对新生代和老年代,是否都使用并行,有不同的回收器选择:
2.1、 ParNew回收器:
(1)特点:
–这个回收器只针对新生代进行并发回收,老年代依然使用串行回收
–回收算法依然和串行回收一样,新生代使用复制算法,老年代使用标记压缩算法
–垃圾回收时, 应用程序仍会暂停, 只不过由于是多线程回收, 在多核CPU上,回收效率会高于串行回收器, 反之在单核CPU, 效率会不如串行回收器
(2)设置参数:
-XX:+UseParNewGC 如果要进一步指定并发的线程数,可以配置一下参数:
-XX:ParallelGCThreads
串行回收器的执行流程如下所示:
2.2、Parallel回收器:
依然是并行回收器,但这种回收器有两种配置
一种类似于ParNEW:
(1)特点:
–新生代使用并行回收、老年代使用串行回收
–它与ParNew的不同在于它在设计目标上更重视吞吐量
–可以认为在相同的条件下它比ParNew更优。
(2)设置参数:
-XX:+UseParallelGC
另外一种配置则不同于ParNew:
(1)特点:
–对于新生代和老年代均适应并行回收
(2)设置参数:
-XX:+UseParallelOldGC
Parallel回收器的流程和ParNew的流程是一致的,如下图:
3、>>CMS回收器(Concurrent Mark Sweep,并发\标记清除):
CMS回收器: Concurrent Mark Sweep,并发标记清除。注意这里注意两个词:并发、标记清除。
(1)特点:
–是可以与应用程序并发执行、交替执行, 非独占式的回收器, 大部分时候应用程序不会停止运行
–是一种针对老年代的回收器,不对新生代产生作用
–标记清除表示这种回收器不是使用的是标记整理算法,这和前面介绍的串行回收器和并发回收器有所不同, 因此回收后会有内存碎片, 可以使参数设置进行内存碎片的压缩整理
–与ParallelGC和ParallelOldGC不同, CMS主要关注系统停顿时间 ,这种回收器优点在于减少了应用程序停顿的时间,因为它不需要应用程序完成暂定等待垃圾回收,而是与垃圾回收并发执行。
(2)CMS主要步骤:
1. 初始标记 :标记从GC Root可以直接可达的对象;
2. 并发标记(应用程序线程一起) :主要标记过程,标记全部对象;
3. 预清理
4. 重新标记 :由于并发标记时,用户线程依然运行,因此在正式清理前,再做依次重新标记,进行修正。
5. 并发清理(用户线程一起) :基于标记结果,直接清理对象。
6. 并发重置
–>注:初始标记与理新标记是独占系统资源的,不能与用户线程一起执行,而其它阶段则可以与用户线程一起执行
(3)设置参数:
-XX:+UseConcMarkSweepGC 老年代使用CMS回收器, 新生代使用ParNew回收器
流程如下图所示:
注:初始标记与重新标记是独占系统资源的,不能与用户线程一起执行,而其它阶段则可以与用户线程一起执行 。
从上图可以看到标记过程分三步:初始标记、并发标记、重新标记。并发标记是最主要的标记过程,而这个过程是并发执行的,可以与应用程序线程同时进行,初始标记和重新标记虽然不能和应用程序并发执行,但这两个过程标记速度快,时间短,所以对应用程序不会产生太大的影响。最后并发清除的过程,也是和应用程序同时进行的,避免了应用程序的停顿。
CMS的优缺点:
优点:就是减少了应用程序的停顿时间,让回收线程和应用程序线程可以并发执行。但它也不是完美的,
缺点:从他的运行机制可以看出,因为它不像其他回收器一样集中一段时间对垃圾进行回收,并且在回收时应用程序还是运行,因此它的回收并不彻底。这也导致了CMS回收的频率相较其他回收器要高,频繁的回收将影响应用程序的吞吐量。
4、>>G1回收器(jdk1.7后全新的回收器, 试图用于取代CMS):
G1回收器是jdk1.7以后推出的回收器,试图取代CMS回收器。
不同于其他的回收器、G1将堆空间划分成了互相独立的区块。每块区域既有可能属于老年代、也有可能是新生代,并且每类区域空间可以是不连续的(对比CMS的老年代和新生代都必须是连续的)。这种将老年代区划分成多块的理念源于:当并发后台线程寻找可回收的对象时、有些区块包含可回收的对象要比其他区块多很多。虽然在清理这些区块时G1仍然需要暂停应用线程、但可以用相对较少的时间优先回收包含垃圾最多区块。这也是为什么G1命名为Garbage First的原因:第一时间处理垃圾最多的区块。
(1)特点:
–独特的垃圾回收策略, 属于分代垃圾回收器
–使用分区算法, 不要求eden, 年轻代或老年代的空间都连续
–并行性: 回收期间, 可由多个线程同时工作, 有效利用多核cpu资源
–并发性: 与应用程序可交替执行, 部分工作可以和应用程序同时执行,
–分代GC: 分代收集器, 同时兼顾年轻代和老年代
–空间整理: 回收过程中, 会进行适当对象移动, 减少空间碎片
–可预见性: G1可选取部分区域进行回收, 可以缩小回收范围, 减少全局停顿
(2)设置参数:
-XX:+UseG1GC 打开G1收集器开关,
G1相对CMS回收器来说主要优点在于:
1、因为划分了很多区块,回收时减小了内存碎片的产生;
2、G1适用于新生代和老年代,而CMS只适用于老年代。
到此,JVM垃圾回收器的探究已完毕,下面列出这些常使用的垃圾回收器配置参数的快照:
-XX:+UseSerialGC:
在新生代和老年代使用串行收集器
-XX:+UseParNewGC:
在新生代使用并行收集器
-XX:+UseParallelGC :
新生代使用并行回收收集器,更加关注吞吐量
-XX:+UseParallelOldGC:
老年代使用并行回收收集器
-XX:ParallelGCThreads:
设置用于垃圾回收的线程数
-XX:+UseConcMarkSweepGC:
新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:
设定CMS的线程数量
-XX:+UseG1GC:
启用G1垃圾回收器
更多技术文章,扫描下方二维码关注我!!!
本文分享自微信公众号 - 一只蓝色猿(umizhang0910)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/3970380/blog/4476332