深入JVM虚拟机(四) Java GC收集器

深入JVM虚拟机(四)
Java GC收集器

1 GC收集器

1.1 Serial串行收集器

串行收集器主要有两个特点:第一,它仅仅使用单线程进行垃圾回收;第二,它独占式的垃圾回收。

在串行收集器进行垃圾回收时,Java
应用程序中的线程都需要暂停(“StopThe World”),等待垃圾回收的完成,这样给用户体验造成较差效果。虽然如此,串行收集器却是一个成熟、经过长时间生产环境考验的极为高效的收集器。新生代串行处理器使用复制算法,实现相对简单,逻辑处理特别高效,且没有线程切换的开销。在诸如单
CPU 处理器或者较小的应用内存等硬件平台不是特别优越的场合,它的性能表现可以超过并行回收器和并发回收器。在 HotSpot
虚拟机中,使用-XX:+UseSerialGC
参数可以指定使用新生代串行收集器和老年代串行收集器。

-  新生代、老年代使用串行回收。

-  新生代使用复制算法。

-  老年代使用标记-压缩算法。

新生代日志输出:

0.844: [GC 0.844: [DefNew: 17472K->2176K(19648K), 0.0188339secs] 17472K->2375K(63360K), 0.0189186 secs] [Times: user=0.01 sys=0.00,real=0.02 secs]

8.259: [Full GC 8.259: [Tenured: 43711K->40302K(43712K),0.2960477 secs] 63350K->40302K(63360K), [Perm : 17836K->17836K(32768K)],0.2961554 secs]

[Times: user=0.28 sys=0.02, real=0.30 secs]

1.2 ParNew并行收集器

并行收集器是工作在新生代的垃圾收集器,它只简单地将串行回收器多线程化。它的回收策略、算法以及参数和串行回收器一样。并行回收器也是独占式的回收器,在收集过程中,应用程序会全部暂停。

但由于并行回收器使用多线程进行垃圾回收,因此,在并发能力比较强的 CPU上,它产生的停顿时间要短于串行回收器,而在单
CPU 或者并发能力较弱的系统中,并行回收器的效果不会比串行回收器好,由于多线程的压力,它的实际表现很可能比串行回收器差。开启并行回收器可以使用参数-XX:+UseParNewGC,该参数设置新生代使用并行收集器,老年代使用串行收集器。使用-XX:ParallelGCThreads
限制线程数量。

ParNew并行收集器日志输出:

0.834:[GC 0.834: [ParNew:13184K->1600K(14784K),
0.0092203 secs] 13184K->1921K(63936K), 0.0093401secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

1.3 Parallel收集器

Parallel收集器类假于ParNew并行收集器,它使用复制算法的收集器。从表面上看,它和并行收集器一样都是多线程、独占式的收集器。但是,并行回收收集器有一个重要的特点:它非常关注系统的吞吐量。

Parallel收集器可以使用以下参数启用:

-XX:+UseParallelGC:新生代使用并行回收收集器,老年代使用串行收集器。

-XX:+UseParallelOldGC:新生代和老年代都是用并行回收收集器。

这两个参数是矛盾的。因为停顿时间和吞吐量不可能同时调优:

-XX:MaxGCPauseMills:最大停顿时间,单位毫秒。GC尽力保证回收时间不超过设定值。

-XX:GCTimeRatio:垃圾收集时间占总时间的比,0-100的取值范围,默认99,即最大允许1%时间做GC。

Parallel收集器日志输出:

1.500:[Full GC [PSYoungGen:2682K->0K(19136K)]
[ParOldGen: 28035K->30437K(43712K)] 30717K->30437K(62848K)
[PSPermGen:10943K->10928K(32768K)], 0.2902791 secs] [Times: user=1.44 sys=0.03,real=0.30 secs]

1.4 CMS 收集器

CMS
是 Concurrent Mark Sweep
的缩写,意为并发标记清除,从名称上可以得知,它使用的是标记-清除算法,同时它又是一个使用多线程并发回收的垃圾收集器。与并行回收收集器不同,CMS
收集器主要关注于系统停顿时间。

CMS
工作时,主要步骤有:

初始标记(CMS initial mark):
根可以直接关联到的对象,速度比较快。

并发标记(CMS concurrent mark):主要标记过程,标记全部对象。注:和用户线程一起并发运行。

重新标记(CMS remark):
由于并发标记时,用户线程依然运行,因此在正式清理前,再做修正。

并发清除和并发重置(CMS concurrent sweep):
基于标记结果,直接清理对象。

其中初始标记和重新标记是独占系统资源的,而并发标记、并发清除和并发重置是可以和用户线程一起执行的。因此,从整体上来说,CMS
收集不是独占式的,它可以在应用程序运行过程中进行垃圾回收。

CMS
收集器在其主要的工作阶段虽然没有暴力地彻底暂停应用程序线程,但是由于它和应用程序线程并发执行,相互抢占 CPU,所以在
CMS 执行期内对应用程序吞吐量造成一定影响。CMS
默认启动的线程数是(ParallelGCThreads+3)/4),ParallelGCThreads
是新生代并行收集器的线程数,也可以通过-XX:ParallelCMSThreads
参数手工设定 CMS的线程数量。当
CPU 资源比较紧张时,受到 CMS收集器线程的影响,应用程序的性能在垃圾回收阶段可能会非常糟糕。

标记-清除算法将会造成大量内存碎片,离散的可用空间无法分配较大的对象。在这种情况下,即使堆内存仍然有较大的剩余空间,也可能会被迫进行一次垃圾回收,以换取一块可用的连续内存,这种现象对系统性能是相当不利的,为了解决这个问题,CMS
收集器还提供了几个用于内存压缩整理的算法。

-XX:+UseCMSCompactAtFullCollection参数可以使
CMS 在垃圾收集完成后,进行一次内存碎片整理。内存碎片的整理并不是并发进行的。

-XX:CMSFullGCsBeforeCompaction参数可以用于设定进行多少次
CMS 回收后,进行一次内存压缩。

-XX:ParallelCMSThreads设定CMS的线程数量。

CMS收集器日志输出:

1.662: [GC [1
CMS-initial-mark: 28122K(49152K)] 29959K(63936K), 0.0046877
secs] [Times:user=0.00 sys=0.00, real=0.00 secs]

1.666: [CMS-concurrent-mark-start]

1.699: [CMS-concurrent-mark:
0.033/0.033 secs] [Times: user=0.25 sys=0.00, real=0.03 secs]

1.699: [CMS-concurrent-preclean-start]

1.700: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]

1.700: [GC[YG occupancy: 1837 K (14784 K)]1.700: [Rescan(parallel) , 0.0009330 secs]1.701: [weak refs processing, 0.0000180 secs]

[1 CMS-remark:28122K(49152K)]
29959K(63936K), 0.0010248 secs] [Times: user=0.00 sys=0.00,real=0.00 secs]

1.702: [CMS-concurrent-sweep-start]

1.739: [CMS-concurrent-sweep:
0.035/0.037 secs] [Times: user=0.11 sys=0.02, real=0.05 secs]

1.739: [CMS-concurrent-reset-start]

1.741:[CMS-concurrent-reset:0.001/0.001
secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

CMS特点:

-  尽可能降低停顿

-  会影响系统整体吞吐量和性能

比如,在用户线程运行过程中,分一半CPU去做GC,系统性能在GC阶段,反应速度就下降一半

-  清理不彻底

因为在清理阶段,用户线程还在运行,会产生新的垃圾,无法清理。

因为和用户线程一起运行,不能在空间快满时再清理。

-XX:CMSInitiatingOccupancyFraction设置触发GC的阈值

如果不幸内存预留空间不够,就会引起concurrent mode failure,产生这种问题,通常都使用串行收集器再次垃圾收集,在这种情况下内存基本被占用满了,通常GC停顿的时间较长。

CMS收集器日志输出:

33.348: [Full GC 33.348: [CMS33.357: [CMS-concurrent-sweep:0.035/0.036 secs] [Times: user=0.11 sys=0.03, real=0.03 secs]

(concurrentmode failure):
47066K->39901K(49152K), 0.3896802 secs]60771K->39901K(63936K), [CMS Perm : 22529K->22529K(32768K)], 0.3897989secs] [Times: user=0.39 sys=0.00, real=0.39 secs]

1.5 G1收集器(Garbage First)

G1收集器与前面的CMS收集器相比有两个显著的改进:一是G1收集器是基于“标记-整理”算法实现的收集器,也就是说它不会产生空间碎片,这对于长时间运行的应用系统来说非常重要。二是它可以非常精确地控制停顿,既能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。G1收集器可以实现在基本不牺牲吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力地避免全区域的垃圾收集,之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个Java堆(包括新生代、老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这就是Garbage
First名称的来由)。区域划分及有优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。

2 GC收集器参数

2.1 收集器参数总结

1、
Serial串行收集器相关的参数


-XX:+UseSerialGC


新生代和老年代使用串行回收器。


-XX:SurvivorRatio


设置eden区大小和survivior区大小的比例。


-XX:PretenureSizeThreshold


设置大对象直接进入老年代的阈值。当对象的大小超过这个值时,将直接在老年代分配。


-XX:MaxTenureSizeThreshold


设置对象进入老年代的年龄的最大值。每一次Minor

2、
ParNew并行收集器相关的参数


-XX:+UseParNewGC


在新生代使用并行收集器。


-XX:+UseParallelGC


新生代使用并行回收收集器


-XX:+UseParallelOldGC


老年代使用并行回收器。


-XX:ParallelGCThreads


设置用于垃圾回收的线程数。通常情况下可以和CPU数量相等,但在CPU数量比较多的情况下,设置相对较小的数值也是合理的。


-XX:MaxGCPauseMills


设置最大垃圾收集停顿时间。它的值是一个大于0的正数。收集器在工作时,会调整java堆大小或者其他一些参数,尽可能地把停顿时间控制在MaxGCPauseMills以内。


-XX:GCTimeRatio


设置吞吐量大小。它的值时一个0到100之间的整数。假设GCTimeRatio的值为n,那么系统将花费不超过1/(1+n)的时间用于垃圾收集。


-XX:+UseAdaptiveSizePolicy


打开自适应GC策略。在这种模式下,新生代的大小、eden和survivior的比例、晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。

3、
CMS
收集器相关的参数


-XX:+UseConcMarkSweepGC


新生代使用并行收集器,老年代使用CMS+串行收集器。


-XX:ParallelCMSThreads


设定CMS的线程数量。


-XX:CMSInitiatingOccupancyFraction


设置CMS收集器在老年代空间被使用多少后触发,默认为68%。


-XX:+UseCMSCompactAtFullCollection


设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。


-XX:CMSFullGCsBeforeCompaction


设定进行多少次CMS垃圾回收后,进行一次内存压缩。


-XX:+CMSClassUnloadingEnabled


允许对类元数据区进行回收。


-XX:CMSInitiatingPermOccupancyFraction


当永久区占用率达到这一百分比时,启动CMS回收(前提是-XX:+CMSClassUnloadingEnabled激活了)。


-XX:CMSInitiatingPermOccupancyOnly


表示只在到达阈值的时候才进行CMS回收。


-XX:+CMSIncrementalMode


使用增量模式,比较适合单CPU。增量模式在JDK8中标记为废弃,并且将在JDK9中彻底移除。

4、
G1收集器相关的参数


-XX:+UseG1GC


使用G1回收器。


-XX:MaxGCPauseMillis


设置最大垃圾收集停顿时间。


-XX:GCPauseIntervalMillis


设置停顿间隔时间。

--以上为《深入JVM虚拟机(四) Java GC收集器》,如有不当之处请指出,我后续逐步完善更正,大家共同提高。谢谢大家对我的关注。

——厚积薄发(yuanxw)

时间: 2024-10-09 21:33:45

深入JVM虚拟机(四) Java GC收集器的相关文章

深入JVM虚拟机(三) Java GC垃圾收集

深入JVM虚拟机(三) Java GC垃圾收集 1 Java GC垃圾收集 1.1 GC的概念 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制.概括地说,该机制对 JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回

Java GC收集器配置说明

根据Java GC收集器具体分类,我们可以看出JVM根据需求不同提供了三种选择:串行收集器.并行收集器.并发收集器. 串行收集器只适用于小数据量的情况,我们主要了解一下并行收集器和并发收集器.默认情况下,JDK5.0以前都是使用串行收集器,如果需要使用其他收集器需要在启动的是时候加入相应的参数.JDK5.0以后,JVM会根据当前系统的配置进行判断. 我们先了解一下什么是并行和并发? 并行:指多条垃圾收集器线程并行工作,但此时仍是“Stop The World”状态,即用户线程处于等待状态: 并发

java虚拟机学习总结之GC回收算法与GC收集器

GC回收算法 1.标记清除算法分为标记阶段和清除阶段标记阶段:通过特定的判断方式找出无用的对象实例并将其标记清除阶段:将已标记的对象所占用的内存回收缺点:运行多次以后容易产生空间碎片,当需要一整段连续内存时虽然空间足够但是无法分配,会多次触发GC操作. 2.复制算法为了提高标记清除算法的效率,减少内存碎片的产生而出现的,该算法将内存空间分为两个完全相同的两部分,每次只使用其中的一部分.分为标记阶段.复制阶段和清除阶段标记阶段:同标记清除算法的标记阶段一致复制阶段:将为标记的对象全部复制到另一块未

JAVA G1收集器 第11节

JAVA G1收集器 第11节 上两章我们讲了新生代和年老代的收集器,那么这一章的话我们就要讲一个收集范围涵盖整个堆的收集器——G1收集器. 先讲讲G1收集器的特点,他也是个多线程的收集器,能够充分利用多个CPU进行工作,收集方式也与CMS收集器类似,因此不会有太久的停顿. 虽然回收的范围是整个堆,但还是有分代回收的回收方式.在年轻代依然采用复制算法:年老代也同样采用“标记-清除-整理”算法.但是,新生代与老年代在堆内存中的布局就和以往的收集器有着很大的区别:G1将整个堆分成了一个个大小相等的独

HotSpot VM GC收集器的合名问题

最近分析HotSpot VM GC日志,就各种收集器的名称搞晕掉了,幸好参考R大(RednaxelaFX )一些回复和文章.整理在此文,以方便自已日后查阅,也可让有需要的同学少走弯路,追本溯源,一切从DefNew的来因说起. DefNew: 是使用-XX:+UseSerialGC(新生代,老年代都使用串行回收收集器) ParNew: 是使用-XX:+UseParNewGC(新生代使用并行收集器,老年代使用串行回收收集器)或者-XX:+UseConcMarkSweepGC(新生代使用并行收集器,老

JVM的四种GC算法

程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC).关于 JVM 的 GC 算法主要有下面四种: 1.引用计数算法(Reference counting) 每个对象在创建的时候,就给这个对象绑定一个计数器.每当有一个引用指向该对象时,计数器加一:每当有一个指向它的引用被删除时,计数器减一.这样,当没有引用指

java - GC垃圾收集器详解(二)

CMS收集器 CMS收集器(ConcurrentMarkSweep:并发标记清除)是一种以获取最短回收停顿时间为目标的收集器. 适合应用在互联网站或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短. CMS非常适合堆内存大.CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器. Concurrent Mark Sweep 并发标记清除,并发收集低停顿,并发指的是与用户线程一起执行 开启该收集器的JVM参数:-XX:+UseConcMarkSreepGC,

java - GC垃圾收集器详解(三)

以前收集器的特点 年轻代和老年代是各自独立且连续的内存块 年轻代收集必须使用单个eden+S0+S1进行复制算法 老年代收集扫描整个老年代区域 都是以尽可能少而快速地执行GC为设计原则 G1是什么 G1(Garbage-Frist)收集器,是一款面向服务端应用的收集器 从官网的描述中,我们知道G1是一种服务器端的垃圾收集器,应用在多处理器和大容量内存环境中,在提高吞吐量的同时,尽可能的满足垃圾收集暂停时间的要求.另外,它还具有以下特性: 像CMS收集器一样,能与应用程序线程并发执行 整理空闲空间

JVM学习3--GC参数及收集器

一.串行收集器 -XX:+UseSerialGC 从第二张图的时间可以看出来,复制算法的效率要比标记压缩算法高的多. 二.并行收集器 -XX: +UseParNewGC (新生代并行,老年代串行) -XX: +UseParallelGC (新生代并行,老年代串行) -XX: +UsePrallelOldGC (新生代老年代都是串行) 注意:多线程不一定更快,这就跟写程序一样,要注意使用场景. 图示: 注意图中红字,PSYoungGen和ParOldGen表示新生代老年代都用的并行收集器,所以此时