JVM GC系列 — GC收集器
一.前言
前文学习了各种GC回收算法,掌握了GC回收的原理,但是真正的GC实现却尤为复杂,本篇文章将主要介绍各种GC收集器。
目前主流的HotSpot VM支持多种虚拟机,这些虚拟机也体现了GC的发展历程,从单线程GC到多线程GC,分代GC到G1 GC。
本文主要从以下几个方面介绍GC收集器:
- 各种GC的特点
- GC匹配和参数使用
- GC日志格式
- 常用的GC参数总结
### 二.各种GC的特点
HotSpot中采用分代GC,从早期的单线程串行Garbage Collector到后面的多线程并行Garbage Collecot,衍生出了很多款Collector。
其中负责收集年轻代:
- Serial:单线程串行收集器,使用复制算法回收年轻代
- ParNew:多线程并行收集器,使用复制算法回收年轻代
- Parallel Scavenge:多线程并行收集器,使用复制算法回收年轻代
其中负责收集老年代:
- Serial Old:类似Serial,单线程串行收集器,使用标记整理算法回收老年代
- CMS:并发标记整理的收集器,使用标记清除算法回收老年代
- Parallel Old:类似ParNew和Parallel Scavenge,使用标记整理算法回收老年代
1.Serial收集器
Serial收集器是一款非常古老的收集器,它使用单线程串行方式回收年轻代,会产生STW。
Note:
STW即Stop The World,即停止所有用户线程,只有GC线程在运行。
每次进行GC时,首先停顿所有的用户线程,然后只有一个GC线程回收年轻代中的死亡对象。在Java Client模式中,默认任然使用Serial,因为Client模式主要针对桌面应用,一般内存较小,在百M范围内,使用单线程收集Serial效率非常高,可以带来很少时间的停顿,用户体检非常好。
2.ParNew收集器
在早期,只有单线程收集器时,年轻代别无选择。后续又演变成多线程GC年轻代,便衍生出ParNew这款并行收集器,它的并行实现主要是在GC期间使用多线程回收年轻代。
这款并行收集器在GC期间,也需要STW。一般多数用于Server端的年轻代GC。
3.Parallel Scavenge收集器
顾名思义,这个款年轻代收集器也是并行收集器,和ParNew的功能差不多,同样适用复制算法。但是它更注重系统运行的吞吐量。这里说的吞吐量,指的是CPU用于运行应用程序的时间和CPU总时间的占比,吞吐量 = 代码运行时间 / (代码运行时间 + 垃圾收集时间)。但是它的来源比较奇葩,没有遵循GC框架,导致和CMS不能兼容。关于这点可以参考:
ParNew 和 PSYoungGen 和 DefNew 是一个东西么?
4.Serial Old收集器
该收集器和Serial收集器的功能一样,都是单线程串行收集器,GC期间也会STW。但是它用于收集老年代且使用了标记整理算法,这两点它和Serial收集器不一样。主要也是应用在Client模式下的桌面应用中。
5.Parallel Old收集器
Parallel Old和ParNew和Parallel Scavenge类似,是一款老年代的多线程并行收集器。一般只配合Parallel Scavenge使用。
6.CMS收集器
CMS(Concurrent Mark Sweep 并发标记清理)收集器是日常应用中最常被使用的收集器。它主要是为了减少停顿的时间,降低延迟而生,多应用对实时性要求比较的应用场景,如:互联网应用。
它主要分为四个过程:
- 初始标记:这阶段将标记不可达对象,标记阶段将暂停所有用户线程,造成STW。但是这阶段只是标记出GC Roots,停顿时间相对较短。
- 并发标记:这阶段GC线程将会和用户线程同时运行,将从初始阶段标记出的GC Roots出发标记老年代所有对象
- 重新标记:这阶段将暂停所用用户线程,造成STW。但是同样相对较短,主要是为了重新标记出在并发阶段发生引用变化的对象,因为并发标记阶段是和用户线程并发运行,可能会造成对象的引用关系发生变化。
- 并发清除:这是最后一个阶段,也是和用户线程同时运行的。将并发的清理掉被标记的死亡对象。
其中初始标记和重新标记仍然会STW暂停用户线程,但是这两个过程的停顿时间相对于并发标记和并发清除而言相对较短,而并发标记和并发清除阶段GC线程则可以和用户线程并发运行。
由于CMS收集器同样使用标记清除算法,所以存在内存碎片问题,从而可能造成大对象无法分配发生提前GC。所以CMS收集器又提供了参数控制其进行内存碎片整理,默认是开启状态,这个过程是非常长的。
三.GC匹配和参数使用
从以上内容介绍,可以看出分代GC分为很多种,随着演化过程,每种都有各自的应用场景。从其收集特点上可以分为三类:
- 单线程串行收集
- 多线程并发串行收集
- 多阶段并行收集
虽然这些分代收集器种类繁多,但是他们之间有相互匹配,并非任意使用。配对的使用情况以及参数见下表:
young | old | 参数 |
---|---|---|
Serial | Serial old | -XX:+UseSerialGC |
ParNew | Serial old | -XX:+UseParNewGC |
Parallel Scavenge | Serial old | -XX:+UseParallelGC |
Parallel Scavenge | Parallel Old | -XX:+UseParallelOldGC |
ParNew | CMS + Serial Old | -XX:+UseConcMarkSweepGC |
Serial | CMS | -XX:+UseConcMarkSweepGC -XX:-UseParNewGC |
### 四.GC日志格式
GC收集器众多,每种GC收集器的GC日志格式都不一样。这里笔者做了下总结,同样是针对以上的各种匹配情况做了日志格式的收集。
1.Serial + Serial old格式
0.299: [GC (Allocation Failure) 0.299: [DefNew: 1770K->428K(4928K), 0.0019955 secs] 9962K->8620K(15872K), 0.0020405 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.304: [GC (Allocation Failure) 0.304: [DefNew (promotion failed) : 4612K->4193K(4928K), 0.0014249 secs]0.305: [Tenured: 8588K->4499K(10944K), 0.0034912 secs] 12804K->4499K(15872K), [Metaspace: 3094K->3094K(1056768K)], 0.0049774 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
使用Serial + Serial Old搭配式,年轻代收集将会是DefNew,老年代将会是Tenured。
1. ParNew + Serial old格式
0.243: [GC (Allocation Failure) 0.243: [ParNew: 1770K->470K(4928K), 0.0029402 secs] 9962K->8662K(15872K), 0.0029933 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
0.251: [GC (Allocation Failure) 0.251: [ParNew (promotion failed): 4566K->4096K(4928K), 0.0009985 secs]0.252: [Tenured: 8632K->4516K(10944K), 0.0025514 secs] 12758K->4516K(15872K), [Metaspace: 3093K->3093K(1056768K)], 0.0035906 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
使用Serial + Serial Old搭配式,年轻代收集将会是ParNew,老年代将会是Tenured。
3.Parallel Scavenge + Parallel Old格式
0.224: [GC (Allocation Failure) [PSYoungGen: 0K->0K(4608K)] 8619K->8619K(15872K), 0.0004876 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.225: [Full GC (Allocation Failure) [PSYoungGen: 0K->0K(4608K)] [ParOldGen: 8619K->8601K(11264K)] 8619K->8601K(15872K), [Metaspace: 3080K->3080K(1056768K)], 0.0046498 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
使用Parallel Scavenge + Parallel Old搭配式,年轻代收集将会是PSYoungGen,老年代将会是ParOldGen。
4.ParNew + CMS格式
0.351: [GC (Allocation Failure) 0.351: [ParNew: 1769K->446K(4928K), 0.0008713 secs] 9961K->8638K(15872K), 0.0009216 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
0.354: [GC (CMS Initial Mark) [1 CMS-initial-mark: 8192K(10944K)] 12734K(15872K), 0.0004513 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.355: [CMS-concurrent-mark-start]
0.355: [CMS-concurrent-mark: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.355: [GC (Allocation Failure) 0.355: [ParNew (promotion failed): 4631K->4267K(4928K), 0.0007242 secs]0.356: [CMS (concurrent mode failure): 8207K->4500K(10944K), 0.0031171 secs] 12823K->4500K(15872K), [Metaspace: 3080K->3080K(1056768K)], 0.0038915 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
使用CMS收集器的GC日志格式非常明显,有CMS的GC过程,年轻代将使用ParNew标志。
### 五.常用的GC参数总结
1.开启GC日志
- -verbose:gc:打印GC日志
- -XX:+PrintGCDateStamps:打印GC日志时间戳
- -XX:PrintGCDetails:打印GC日志详情
- -XX:+PrintGCTimeStamps:打印此次GC距离JVM开始运行的时间
- -XX:+PrintGCApplicationStopedTime:打印GC造成的应用暂停时间
- -XX:+PrintTenuringDistribution:打印对象晋升日志
2.通用参数
- -XX:+HeapDumpOnOutOfMemoryError:内存溢出时,产生heap dump文件
- -Xloggc::将GC日志输出到指定文件
- -XX:-+DisableExplicitGC:禁用System.gc(),该方法默认会触发FGC
- -XX:MaxTenuringThreshold: 新生代 to 区的对象在经过多次 GC 后,如果还没有死亡,则认为他是一个老对象,则可以晋升到老年代,默认是15。但该参数不是唯一决定对象晋升的条件,当 to区不够或者该对象年龄已经达到了平均晋升值或者大对象等等条件
- -XX:TargetSurvivorRatio 决定对何时晋升的不仅只有 XX:MaxTenuringThreshold 参数,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半(默认50%)
- -XX:+UseTLAB:启用线程本地分配缓存,默认开启
- -XX:+PrintTLAB:打印TLAB的使用情况
参考
Our Collectors
ParNew 和 PSYoungGen 和 DefNew 是一个东西么?
JVM GC系列 — GC收集器的更多相关文章
- 深入JVM系列(二)之GC机制、收集器与GC调优
一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代 3.长期存活的 ...
- 深入JVM系列(二)之GC机制、收集器与GC调优(转)
一.回顾JVM内存分配 需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...
- JVM(2)——GC算法和收集器
一.引入 上篇博客<JVM--简介>中主要介绍了JVM的内存模型,思考一下: 为什么要划分堆.栈.方法区等? 为什么把不同种类的数据信息分别存放? 答案可以分为很多很多条,这里就说一个方面 ...
- JVM探秘4---垃圾收集器介绍
Java虚拟机有很多垃圾收集器 下面先来了解HotSpot虚拟机中的7种垃圾收集器:Serial.ParNew.Parallel Scavenge.Serial Old.Parallel Old.CM ...
- JVM之Parallel Scavenge收集器
新生代收集器,复制算法,并行收集,面向吞吐量要求(吞吐量优先收集器). 吞吐量=用户代码运行时间/(用户代码运行时间+垃圾回收时间) -XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间 ...
- 深入理解JVM(③)ZGC收集器
前言 ZGC是一款在JDK11中新加入的具有实验性质的低延迟垃圾收集器,目前仅支持Linux/x86-64.ZGC收集器是一款基于Region内存布局的,(暂时)不设分代的,使用了读屏障.染色指针和内 ...
- JVM GC系列 — GC算法
一.前言 从本篇文章开始,将开始一个新的系列JVM.JVM是一个非常庞大且复制的技术体系,但是对于程序猿的升级,走向更高阶所必要经历的,曾经也下决心要好好学习一番,然而毅力不足都中途放弃. GC的作用 ...
- JVM之Parallel Old收集器
Parallel Scavenge的老年代版本 标记-整理算法 注重吞吐量及cpu资源敏感环境.
- 学习JVM--垃圾回收(二)GC收集器
1. 前言 在上一篇文章中,介绍了JVM中垃圾回收的原理和算法.介绍了通过引用计数和对象可达性分析的算法来筛选出已经没有使用的对象,然后介绍了垃圾收集器中使用的三种收集算法:标记-清除.标记-整理.标 ...
随机推荐
- 《DevOps实践:驭DevOps之力强化技术栈并优化IT运行》
DevOps实践:驭DevOps之力强化技术栈并优化IT运行 主旨 这本书并非坐而论道,而是介绍了DevOps全流程中的许多实践,以及相应工具的运用.虽然随着时代的推移,工具将来可能会过时,但是这些实 ...
- [译]Vulkan教程(28)Image视图和采样器
[译]Vulkan教程(28)Image视图和采样器 Image view and sampler - Image视图和采样器 In this chapter we're going to creat ...
- DBCC TRACEON - 跟踪标志 (Transact-SQL)
跟踪标志用于设置特定服务器特征或更改特定行为. 例如,跟踪标志 3226 是一种常用的启动跟踪标志,可取消显示错误日志中的成功备份消息. 跟踪标志经常用于诊断性能问题或调试存储过程或复杂的计算机系统, ...
- idea创建maven工程
1.右键更目录,new->Module 2.选择Maven,并配置自己的SDK,一般默认的也可以用,点击next进入下一步 3.配置pom文件里的GroupId和Artifactld 4.配置m ...
- C# 使用NAudio合并mp3、wav音频文件
1.什么是wav格式 WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windo ...
- PHP实现微信提现(企业付款到零钱)
怎么开通企业付款到零钱? 有的商户号的产品中心是没有这个功能的,不过,该功能的pid(product id)是5,只要随便进去某一个产品,在地址栏把pid改为5. 即可进入该功能页面,进行开通,不过要 ...
- SpringCloud的入门学习之概念理解、Eureka服务注册与发现入门
1.微服务与微服务架构.微服务概念如下所示: 答:微服务强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题.提供落地对应服务的一个服务应用,狭意的看,可以看作Eclipse里面的一个个微服务 ...
- Selenium模块的安装
Selenium模块 1.安装selenium python2:pip install selenium python3:pip install selenium 2.设置浏览器驱动 解压后必须与浏览 ...
- 缓冲字符流 java.io.BufferedWriter ,java.io.BufferedReader,缓冲字符输出流:PrintWriter
package seday07; import java.io.IOException;import java.io.PrintWriter; /*** @author xingsir * 缓冲字符流 ...
- 【前端知识体系-NodeJS相关】对NodeJS模块机制的理解
1. CommonJS模块规范 1.1 模块引用 var math = require('math'); 1.2 模块定义 [!NOTE] 上下文提供exports对象用于导出当前模块的方法和变量,并 ...