JVM-垃圾回收器详解、参数配置

相关概念

并行和并发

并行(Parallel)
指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

并发(Concurrent)
指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行。而垃圾收集程序运行在另一个CPU上。

Minor GC 和 Full GC

新生代GC(Minor GC)
指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。

老年代GC(Major GC / Full GC)
指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

吞吐量(Throughput)

吞吐量就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即

吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。

假设虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那吞吐量就是99%。

GC Root

GC Root 包含以下对象:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象
  2. 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象
  3. 方法区中类静态属性引用的对象
  4. 方法区中常量引用的对象

Serial/Serial Old 收集器

这是两款最基本的垃圾回收器,一般用于客户端模式下,适合单核或者配置较低的情况。曾经(JDK 1.3.1之前)是虚拟机新生代收集的唯一选择。
在这里插入图片描述

Serial

新生代垃圾收集器,标记复制算法单个垃圾收集线程,会产生Stop The World。

# 添加该参数来显式的使用Serial垃圾收集器。
-XX:+UseSerialGC

Serial Old

老年代垃圾收集器,标记-整理算法单个垃圾收集线程,Stop The World,可作为CMS收集器并发失败时的后备预案。

Par New / Parallel Old 收集器

相比于Serial/Serial Old,这两款垃圾收集器也很类似,主要区别是引入了多个垃圾收集线程,但收集的时候仍然是需要Stop The World的,无法与用户线程并发。

Par New

新生代垃圾收集器,标记复制算法多个垃圾收集线程,Stop The World,经常与CMS垃圾收集器搭配使用。

# 指定使用CMS后,会默认使用ParNew作为新生代收集器。
-XX:+UseConcMarkSweepGC
# 强制指定使用ParNew。   
-XX:+UseParNewGC
# 指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同。
-XX:ParallelGCThreads

Parallel Old

老年代垃圾收集器,标记整理算法多个垃圾收集线程,Stop The World,与Paralle Scavenge收集器搭配使用。

Parallel Scavenge收集器

新生代垃圾收集器,与Parallel Old搭配使用,与Par New 类似,采用多个垃圾收集线程,会产生Stop The World,但是相对于Par New,它有着一些独特的特点,优势。

首先它是一款以吞吐量优先的垃圾收集器,可以通过-XX:GGTimeRatio,来达到设置吞吐量的目的。

另一个特点是它有一个自适应调节策略,可通过-XX:UseAdaptiveSizePolicy这个开关参数开启自适应调节,开启后它将自动调节新生代大小,Eden与Survivor的比例,晋升老年代对象大小等参数值,从而尽量满足设置的吞吐量参数或者停顿时间参数。

# Parallel Scavenge收集器提供了两个参数来用于精确控制吞吐量,
#一是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis参数,
#二是控制吞吐量大小的 -XX:GCTimeRatio参数;#参数允许的值是一个大于0的毫秒数,收集器将尽可能的保证内存垃圾回收花费的时间不超过设定的值(但是,并不是越小越好,GC停顿时间缩短是以牺牲吞吐量和新生代空间来换取的,如果设置的值太小,将会导致频繁GC,这样虽然GC停顿时间下来了,但是吞吐量也下来了)。
-XX:MaxGCPauseMillis# 参数的值是一个大于0且小于100的整数,也就是垃圾收集时间占总时间的比率,默认值是99,就是允许最大1%(即1/(1+99))的垃圾收集时间。
-XX:GCTimeRatio#参数是一个开关,如果这个参数打开之后,虚拟机会根据当前系统运行情况收集监控信息,动态调整新生代的比例、老年大大小等细节参数,以提供最合适的停顿时间或最大的吞吐量,这种调节方式称为GC自适应的调节策略。
-XX:UseAdaptiveSizePolicy

CMS(Concurrent Mark Sweep)收集器

老年代垃圾收集器,与Par New搭配使用。

它是一款以最小回收停顿时间优先的垃圾收集器,也是Hotspot第一款真正采用并发收集算法的垃圾收集器。采用了标记-清除算法,在标记阶段利用增量更新解决并发标记问题。

其缺点也很明显,会产生大量的内存碎片,且吞吐量也不高。在进行Full GC时会对内存碎片利用整理算法进行整理(会Stop The World)。并发清除阶段可能用户线程会没有足够的内存空间分配对象,导致分配失败,此时会以Serial Old收集器作为分配失败的后备预案(会Stop The World)。

在这里插入图片描述
CMS收集器工作的整个流程分为以下4个步骤:

  1. 初始标记(CMS initial mark):仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,需要“Stop The World”。
  2. 并发标记(CMS concurrent mark):进行GC Roots Tracing的过程,在整个过程中耗时最长。
  3. 重新标记(CMS remark):为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。此阶段也需要“Stop The World”。
  4. 并发清除(CMS concurrent sweep)

由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作

优点

CMS是一款优秀的收集器,它的主要优点在名字上已经体现出来了:并发收集、低停顿,因此CMS收集器也被称为并发低停顿收集器(Concurrent Low Pause Collector)。

缺点

  1. CPU资源非常敏感 其实,面向并发设计的程序都对CPU资源比较敏感。在并发阶段,它虽然不会导致用户线程停顿,但会因为占用了一部分线程(或者说CPU资源)而导致应用程序变慢,总吞吐量会降低。
  2. CMS默认启动的回收线程数是(CPU数量+3)/4,也就是当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源,并且随着CPU数量的增加而下降。但是当CPU不足4个时(比如2个),CMS对用户程序的影响就可能变得很大,如果本来CPU负载就比较大,还要分出一半的运算能力去执行收集器线程,就可能导致用户程序的执行速度忽然降低了50%,其实也让人无法接受。
  3. 无法处理浮动垃圾(Floating Garbage) 可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。
  4. 由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生。这一部分垃圾出现在标记过程之后,CMS无法再当次收集中处理掉它们,只好留待下一次GC时再清理掉。
  5. 这一部分垃圾就被称为“浮动垃圾”。也是由于在垃圾收集阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用。
  6. 标记-清除算法导致的空间碎片 CMS是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。
  7. 空间碎片过多时,将会给大对象分配带来很大麻烦,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象。

JVM参数配置

## 新生代 ParNew + 老年代 CMS + 老年代 Serial Old
# 某些版本的参数是这样的: -XX:+UseConcurrentMarkSweepGC
-XX:+UseConcMarkSweepGC# 响应时间优先,停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小年轻代,默认 18446744073709551615  
-XX:MaxGCPauseMillis
# 吞吐量优先,设置JVM吞吐量要达到的目标值, GC时间占用程序运行时间的百分比的差值,默认是 99
# 也就应用程序线程应该运行至少99%的总执行时间,GC占 1%
-XX:GCTimeRatio=99# 并行收集器(ParNew , STW,  YGC)的线程数,默认CPU所支持的线程数,如果CPU所支持的线程数大于8,则 默认 8 + (logical_processor -8)*(5/8)
-XX:+ParallelGCThreads
#  CMS垃圾回收线程数量
-XX:ParallelCMSThreads# 解决 CMS `Memory Fragmentation` 碎片化, 开启FGC时进行压缩,以及多少次FGC之后进行压缩
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=3
# 解决 CMS `Concurrent mode failure` ,`Promotion Failed`晋升失败  
# 使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70# 开启 CMS 元空间的垃圾回收
-XX:+CMSClassUnloadingEnabled
# -XX:CMSInitiatingPermOccupancyFraction  (JDK8已经移除)

G1(Garbage First)收集器

以CMS收集器替代者的身份出现,同样以最小回收停顿时间为目标,是JDK9的默认垃圾收集器JDK8是Parallel Scanvenge + Parallel Old组合)。

它开创了以局部收集思想和面向Region的内存布局,以Region做为最小回收单元,多个Region组成回收机CSet。同样,这款垃圾收集器中也包含着分代收集思想,不过不同于之间的收集器将堆内存划分为新生代,老年代的布局。

G1将堆空间按固定大小(1M-32M可通过启动参数设定)划分为多个Region,每个Region都可以根据需要作为新生代(Eden,Survivor),老年代(Old),或者说大对象(Humongous,大小超过Region一半,当做老年代对待)。

G1的特点是建立了停顿时间模型:在M毫秒的时间片内 消耗在垃圾收集上的时间不超过N毫,通过启动参数+XX:MaxGCPauseMillis可指定最大停顿时间。

实现原理:在垃圾收集过程中,记录每个Region回收耗时等信息,计算出平均值,标准偏差,置信度等统计信息,从而预测出由哪些Region组成的回收集才可以在不超过设置的停顿时间约束下获得最高的收益。

在这里插入图片描述

G1的收集过程如上图所示。其主保证并发标记正确性的解决方案是原始快照(SATB,区别于CMS的增量更新),在筛选回收阶段更新Region统计数据,根据回收价值排序,选择回收集,回收。
所以从整体上看,G1还是基于标记-整理算法的,只实现了标记阶段的与用户线程并发,回收阶段还是要Stop The World。这种方式导致其没有内存碎片问题。但如果能实现其整理阶段的并发,速度就更快了(其实,整理阶段的并发实现还是比价难得,在后来的Shenandoah和ZGC收集器便实现了整理阶段的并发)。

G1具备如下特点

  1. 并行与并发 G1 能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短“Stop The World”停顿时间,部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让Java程序继续执行。
  2. 分代收集 与其他收集器一样,分代概念在G1中依然得以保留。虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但它能够采用不同方式去处理新创建的对象和已存活一段时间、熬过多次GC的旧对象来获取更好的收集效果。
  3. 空间整合 G1从整体来看是基于“标记-整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的。这意味着G1运行期间不会产生内存空间碎片,收集后能提供规整的可用内存。此特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次GC。
  4. 可预测的停顿 这是G1相对CMS的一大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了降低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在GC上的时间不得超过N毫秒,这几乎已经是实时Java(RTSJ)的垃圾收集器的特征了。

G1收集器运行流程

G1收集器的运作大致可划分为以下几个步骤:

  1. 初始标记(Initial Marking) 仅仅只是标记一下GC Roots 能直接关联到的对象,并且修改TAMS(Nest Top Mark Start)的值,让下一阶段用户程序并发运行时,能在正确可以的Region中创建对象,此阶段需要停顿线程,但耗时很短。
  2. 并发标记(Concurrent Marking) 从GC Root 开始对堆中对象进行可达性分析,找到存活对象,此阶段耗时较长,但可与用户程序并发执行。
  3. 最终标记(Final Marking) 为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这阶段需要停顿线程,但是可并行执行。
  4. 筛选回收(Live Data Counting and Evacuation) 首先对各个Region中的回收价值和成本进行排序,根据用户所期望的GC 停顿是时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

JVM参数配置

#  JDK 9开始为默认垃圾回收器
-XX:+UseG1GC# 响应时间优先,建议值,设置最大GC停顿时间(GC pause time)指标(target). 这是一个软性指标(soft goal)
#  JVM 会尽力去达成这个目标. 所以有时候这个目标并不能达成
# G1会尝试调整Young区的块数来达到这个值
-XX:MaxGCPauseMillis
# 响应时间优先,GC的停顿间隔时间,默认0
-XX:GCPauseIntervalMillis
# 吞吐量优先,设置JVM吞吐量要达到的目标值, GC时间占用程序运行时间的百分比的差值,默认是 99
# 也就应用程序线程应该运行至少99%的总执行时间,GC占 1%
-XX:GCTimeRatio=99# 并发回收器(STW   YGC)的工作线程数量,默认CPU所支持的线程数,如果CPU所支持的线程数大于8,则 默认 8 + (logical_processor -8)*(5/8)
-XX:ParallelGCThreads
# G1 并发标记线程数量
-XX:ConcGCThreads# 启动并发GC时的堆内存占用百分比. G1用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比例。默认45%
# 当堆存活对象占用堆的45%,就会启动G1 中Mixed GC
-XX:InitiatingHeapOccupancyPercent
# G1 分区大小,建议逐渐增大该值,1 2 4 8 16 32。
# 随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长。ZGC做了改进(动态区块大小)
-XX:G1HeapRegionSize# 新生代最小比例,默认为5%
# -XX:G1NewSizePercent (JDK8u23已经移除 https://www.oracle.com/technical-resources/articles/java/g1gc.html)
# 新生代最大比例,默认为60%
# -XX:G1MaxNewSizePercent (JDK823已经移除 https://www.oracle.com/technical-resources/articles/java/g1gc.html)
# G1 新生代初始大小,默认为5%
-XX:NewSize
# G1 新生代最大大小
-XX:MaxNewSize

Shenandoah收集器

这是一款低延迟垃圾收集器,其目标是在尽可能对吞吐量影响不大的前提下,实现在任何堆内存大小下都可以把垃圾收集时间限制在10ms以内。它是OpenJDK12正式特性之一,和G1收集器有很多相似之处,甚至公用了一部分源代码。

相比之下,它有许多的改进点。比如实现了并发的整理算法,用连接矩阵替代了G1的记忆集。要实现并发整理却有一个非常大的难点:与用户线程并发的情况下移动对象,用户线程可能在收集线程移动过程中对被移动的对象进行读写访问。Shenandoah采取的解决方案是读屏障+转发指针

​ 读屏障:可以理解为虚拟机层面对对象访问操作的AOP切面,说白了就是在访问对象之前要干点什么事;转发指针:在原有对象布局结构的最前面统一加一个引用字段,在不处于并发移动的情况下,该引用指向对象自己。当对象有了一份新的副本时,只需修改该引用值指向新的副本,虚拟机对旧对向的访问就会转发到新对象上去。

ZGC收集器

它也是一款低延迟收集器,目标同Shenandoah一样,从目前的表现来看,比Shenandoah更强大,是JDK11发布的一款垃圾收集器。它的特点是Region具有动态性—动态创建和销毁,动态的区域容量大小。此外它同样实现了并发的整理算法。其实现方案是:染色指针+多重映射

染色指针:将少量额外的信息直接存储在指针上,在64位操作系统中,Linux系统只支持46位的物理地址空间(64TB),染色指针将这46位中的4位拿出来存储4个标志信息:如对象的三色标记状态、是否进入重分配集(被移动过)等信息;
多重映射:由于处理器可不认识地址中哪几位是真是的寻址地址,哪几位是标记位,所以Hotspot就通过多重映射技术对地址做一个映射,将寻址地址相同,标记位不同的引用都映射到同一块物理地址空间上。

​ ZGC收集器仅从引用上就可以判断一个对象是否处于重分配集中(回收集),若用户访问了重分配集中的对象,将被内存屏障截获,然后根据Region上的转发表将请求转发到新复制的对象上,同时修正引用值,使其指向新对象。

总结

收集器串行、并行或者并发新生代/老年代算法目标适用场景
Serial串行新生代复制算法响应速度优先单CPU环境下Client模式
Serial Old串行老生代标记-整理响应速度优先单CPU环境下Client模式、CMS的后备预案
ParNew并行新生代复制算法响应速度优先多CPU环境时在Server模式与CMS配合
Parallel Scavenge并行新生代复制算法吞吐量优先在后台运算而不需要太多交互的任务
Parallel Old并行老生代标记-整理吞吐量优先在后台运算而不需要太多交互的任务
CMS并发老生代标记-清除响应速度优先集中在互联网网站或B/S系统服务端的Java应用
G1并发新生代和老年代标记-整理+复制算法响应速度优先面向服务端应用,将来替换CMS

拓展

GC相关的JVM参数

内存溢出

# 生产环境一般再额外增加GC日志参数,OOME HeapDump 参数
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/path/to/dir/
#日志文件的输出路径
-Xloggc:/path/to/log/dir/gc-%t.log  
-XX:+PrintGCCause
#输出GC日志
-XX:+PrintGC 
#输出GC的详细日志
-XX:+PrintGCDetails 
#输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCTimeStamps 
#输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintGCDateStamps 
#在进行GC的前后打印出堆的信息
-XX:+PrintHeapAtGC 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/106695.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

半导体制造工艺(一)光刻

在这里开个新专题,主要详细描述半导体制造整个流程中所用到的设备工艺步骤。 在集成电路制造工艺中,光刻是决定集成器件集成度的核心工序,该工序的作用是将图形信息从掩模版(也称掩膜版)上保真传输、转印到半导体材料衬…

【深度学习】 Python 和 NumPy 系列教程(二):Python基本数据类型:3、字符串(索引、切片、运算、格式化)

目录 一、前言 二、实验环境 三、Python基本数据类型 3. 字符串(Strings) 1. 初始化 2. 索引 3. 切片 4. 运算 a. 拼接运算 b. 复制运算 c. 子串判断 d. 取长度 5. 格式化 a. 使用位置参数 b. 使用关键字参数 c. 使用属性访问 f-string…

什么是JavaScript中的严格模式(strict mode)?应用场景是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 严格模式(Strict Mode):⭐ 使用场景⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

ADW300物联网电表支持MODBUSTCP协议、MQTT协议-安科瑞黄安南

摘要 随着通信技术的应用越来越广泛,具有通信功能的电子产品越来越多,同时也随着Wi-Fi无线覆盖网络区域的形成,如何利用无线网络覆盖广、带宽高、低使用费率的优势组建物联网系统,变成了一个很实际的问题。 安科瑞也紧跟趋势推出…

uni-app 使用uCharts-进行图表展示(折线图带单位)

前言 在uni-app经常是需要进行数据展示,针对这个情况也是有人开发好了第三方包,来兼容不同平台展示 uCharts和pc端的Echarts使用差不多,甚至会感觉在uni-app使用uCharts更轻便,更舒服 但是这个第三方包有优点就会有缺点&#xf…

vue使用百度地图实现地点查询

效果 代码 首先在index.html中引入script&#xff1a; <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width,initial-scal…

微服务05-Docker基本操作

Docker的定义 1.什么是Docker Docker是一个快速交付应用、运行应用的技术&#xff1a; 可以将程序及其依赖、运行环境一起打包为一个镜像&#xff0c;可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器&#xff0c;各个应用互不干扰启动、移除都可以通过一行命令完…

【论文笔记】Baidu Apollo EM Motion Planner

文章目录 AbstractI. INTRODUCTIONA. Multilane StrategyB. Path-Speed Iterative AlgorithmC. Decisions and Traffic Regulations II. EM PLANNER FRAMEWORK WITH MULTILANE STRATEGYIII. EM PLANNER AT LANE LEVELA. SL and ST Mapping (E-step)B. M-Step DP PathC. M-Step …

华为云云耀云服务器L实例评测|了解配置和管理L型云服务器

华为云云耀云服务器L实例配置和管理教程 华为云云耀云服务器L实例的介绍概述特点优势与弹性云服务器&#xff08;ECS&#xff09;的对比 注册和创建L型云服务器注册华为云账号创建L型云服务器实例配置实例参数配置其他参数尝试登录 远程登录 L实例查看公网ip通过本地shell远程连…

Date日期工具类(数据库日期区间问题)

文章目录 前言DateUtils日期工具类总结 前言 在我们日常开发过程中&#xff0c;当涉及到处理日期和时间的操作时&#xff0c;字符串与Date日期类往往要经过相互转换&#xff0c;且在SQL语句的动态查询中&#xff0c;往往月份的格式不正确&#xff0c;SQL语句执行的效果是不同的…

【计算机网络】 IP协议格式以及以太网帧结构

文章目录 IP协议格式以太网帧结构 IP协议格式 IP工作在网络层 IP头分为两部分&#xff0c;固定部分和可变部分&#xff0c;固定部分就是一定要带这些数据&#xff0c;正常存储应该是连续的&#xff0c;并不是像图中这样会换行&#xff0c;图中只是为了方便观察。 首先是一个版…

配电网智能软开关(sop)规划模型matlab

目录 1 主要内容 2 部分程序 3 程序结果 1 主要内容 该程序参考文献《基于改进灵敏度分析的有源配电网智能软开关优化配置》&#xff0c;采用二阶锥算法&#xff0c;以改进的IEEE33节点配电系统模型作为分析对象&#xff0c;以联络开关位置作为sop安装备选位置&#xff0c;以…