【五一创作】值得一看的JVM垃圾收集器

简介: 【五一创作】值得一看的JVM垃圾收集器

垃圾收集器

一、常见的垃圾收集器?

常见的垃圾收集器如下:

  • 新生代收集器:Serial、 ParNew、Parallel Scavenge
  • 老年代收集器:Serial Old、Parallel Old、CMS
  • 老年代和新生代收集器:Garbage First (G1)
二、Serial 垃圾收集器(标记复制算法):

Serial是一种应用于新生代的单线程的垃圾回收器,采用标记复制算法。这个收集器是一个单线程的收集器,在工作的时候只会使用一个处理器或一条收集线程去处理工作,重要的是Serial在进行垃圾收集的时候,必须暂停其他所有的线程,包括用户线程。

开启Serial收集器参数:

-XX:+UserSerialGC #选择Serial作为新生代垃圾收集器

Serial的优点:简单高效,在所有收集器中额外内存消耗是最小的,由于是单线程减少了线程阻塞和线程上下文切换。

Serial的缺点:在用户无感知的情况下会暂停用户线程,降低用户体验感。

Serial的应用场景:Client模式(桌面应用)、单核cpu服务器。

三、ParNew垃圾收集器(标记复制算法):

ParNew收集器实质上是Serial收集器的多线程并行版本,他在单核cpu上的表现并不会比Serial好,在多核机器上,其默认开启的收集线程数与cpu数量相等,可以通过下面命令进行修改:

-XX:ParallelGCThreads #设置JVM垃圾收集的线程数

ParNew的优点:随着cpu核心数的增多,可以有效的利用cpu资源。

ParNew的缺点:和Serial一样,因为是采用标记复制回收算法,所以垃圾收集过程中会暂停用户线程。

ParNew的应用场景:ParNew是许多运行在Server模式下的虚拟机中首选的新生代收集器,因为CMS只能和Sarial或者ParNew来配合使用,当在多核系统环境下,首选的就是ParNew。ParNew也是CMS垃圾收集器的默认新生代收集器。

四、Parallel Scavenge垃圾收集器(标记复制算法):

Parallel Scavenge也是一种应用于新生代的多线程垃圾收集器,采用标记复制算法,他于ParNew的不同之处就是Parallel Scavenge收集器的目的是达到一个可控制的吞吐量,而ParNew关注的点在于尽可能的缩短垃圾收集时用户的停顿时间。

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

Parallel Scavenge的优点:有效的利用cpu,吞吐量优先,并且能精确控制。

Parallel Scavenge的缺点:和ParNew一样,因为是采用标记复制回收算法,所以垃圾收集过程中会暂停用户线程。

Parallel Scavenge的应用场景:适用于后台运算而不需要太多交互的分析任务。

Parallel Scavenge提供了两个参数用于精确控制吞吐量:

控制最大垃圾收集停顿时间:

-XX:MaxGCPauseMilis

直接设置吞吐量大小:

-XX:GCTimeRadio
五、Serial Old垃圾收集器(标记复制算法):

Serial Old垃圾收集器是Serial的老年代版本,同样也是一个采用标记复制算法的单线程垃圾收集器。

Serial Old的用途:jdk5以及以前的版本中与Parallel Scavenge收集器来搭配使用,另外一种就是作为CMS收集器失败时的候选备案。

六、Parallel Old垃圾收集器(标记整理算法):

Parallel Old是Parallel Scavenge收集器的老年代版本,支持多线程并行收集,他采用的是标记整理回收算法。

七、CMS垃圾收集器(标记清除算法):

CMS收集器是一种以获得最短回收停顿时间为目的的收集器,支持多线程并行收集,并且采用标记清除算法。

CMS的执行步骤大致可以分为四步:

  1. 初始标记:需要暂停用户线程,初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快。
  2. 并发标记:不需要暂停用户线程,并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长,但是不需要停顿用户线程,可以与垃圾收集器一起并行运行。
  3. 重新标记:需要暂停用户线程,重新标记则是为了修正 并发标记 阶段,因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。
  4. 并发清除:并发清除阶段会清理删除掉标记阶段的已经死亡的对象,由于不需要移动存活的对象,所以这个阶段也是可以和用户线程同时并发的。

CMS收集器的优点:支持并发收集,低停顿,几乎不会暂停用户线程。

CMS收集器的缺点:

  1. CMS收集器对处理器的资源非常敏感,在并发阶段,他虽然不会导致用户停顿,但是他却因占用了一部分线程(或者处理器的计算能力)而导致应用程度变慢,降低吞吐量。CMS默认启动的回收线程数是(处理器核心数 + 3)/ 4,也就是说如果处理器核心数在4个以上,并发收集线程只占用不少于百分之25的处理器运算资源,并且会随着cpu核心数的增多而下降。
  2. 在CMS并发标记和并发清理阶段,用户线程还是会继续运行的,程序自然就会伴随着有新的垃圾对象不断产出,但这一部分对象是出现在标记过程结束之后,CMS无法在当次收集中处理掉他们,只能留在下一次手机时才清理,这部分垃圾成为浮动垃圾。同样也是因为在垃圾收集阶段用户线程还会持续运行,那就还需要预留足够的内存空间提供给用户线程使用,因此CMS不能像其他垃圾收集器那样等到老年代几乎填满了在进行回收。如果CMS预留的空间无法满足程序分配的新对象,就会出现一次并发失败:这个时候需用冻结用户所有线程,临时采用Serial Old收集器来重新进行老年代的垃圾收集。
  3. CMS是一种基于标记清除算法的回收器,在收集结束的时候会产生大量的空间碎片,空间碎片太多的时候将会给大对象的分配带来麻烦,这就会出现老年代还有很多剩余空间,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

如果解决CMS收集器提前Full GC问题:

CMS提供了两个参数

-XX:UserCMSCompactAtFullCollection #开启碎片整理(默认是开的)
-XX:CMSFullGCsBeforeCompaction #执行多少次不压缩的Full GC之后,跟着来一次压缩的Full GC
八、G1收集器(标记整理算法):

G1收集器是一款面向服务端应用的垃圾收集器,目前是JDK9的默认垃圾收集器。与其他收集器相比,G1具有如下特点:

  1. 并行与并发:G1能够充分利用多cpu,多核环境下的硬件优势。
  2. 分代收集:能够采用不同的方式去处理新创建的对象和已经存活了一段时间的对象,不需要与其他收集器进行合作。
  3. 空间整合:G1整体上是采用标记整理来实现的垃圾收集器,从局部上看是基于复制算法实现的,因此运行期间不会产生空间碎片。
  4. 可预测的停顿模型:G1能建立可预测的时间停顿模型,能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不超过N毫秒。

G1收集器将java堆划分为多个大小相等的独立区域(Region)

每一个方块就是一个区域,每个区域可能是 Eden、Survivor、老年代,每种区域的数量也不一定。JVM 启动时会自动设置每个区域的大小(1M ~ 32M,必须是 2 的次幂),最多可以设置 2048 个区域(即支持的最大堆内存为 32M*2048 = 64G),假如设置 -Xmx8g -Xms8g,则每个区域大小为 8g/2048=4M。

G1收集器可以有计划地避免在整个Java堆全区域的垃圾收集。G1可以跟踪各个Region里面垃圾堆积的价值大小(回收所获得的空间大小及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,收集加载最大的region,这种方式保证了有限时间内可以获取尽可能多高的收集效率。

为了在 GC Roots Tracing 的时候避免扫描全堆,在每个 Region 中,都有一个 Remembered Set 来实时记录该区域内的引用类型数据与其他区域数据的引用关系(在前面的几款分代收集中,新生代、老年代中也有一个 Remembered Set 来实时记录与其他区域的引用关系),在标记时直接参考这些引用关系就可以知道这些对象是否应该被清除,而不用扫描全堆的数据。

G1收集器的优点:

  • 可指定最大停顿时间,该值要合理的进行设置,如果设置的太小,会使得每次筛选出的回收集只占堆内存的很小一部分,收集速度跟不上分配速度,导致垃圾堆积,最终产生Full GC,通常该为100~300ms较为合理
  • 按受益动态确定回收集
  • 低内存碎片,从整体上看,G1采用“标记-整理”的垃圾回收算法,从局部上看又是基于“标记-复制”算法实现,这两种算法使得G1在GC后不会产生内存碎片,有利于程序的长时间运行

G1收集器的缺点:

  • 内存占用高,由于堆内存被划分为许多个小的Region分区数量,面对跨Region对象引用问题,每个Region分区都需要独立维护一份记忆集,使得用于维持G1正常运行的额外内存空间占到了总堆内存空间的10%~20%。
  • 执行负载高,CMS用写后屏障来更新维护卡表,G1除使用写后屏障来更新维护卡表外,为了实现原始快照搜索算法,还需要使用写前屏障来跟踪并发时的指针变化情况。


相关文章
|
1月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
51 2
|
3月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
3月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
27 3
|
3月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
327 0
|
3月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
181 0
|
3月前
|
算法 Java 程序员
【JVM的秘密花园】揭秘垃圾收集器的神秘面纱!
【8月更文挑战第25天】在Java虚拟机(JVM)中,垃圾收集(GC)自动管理内存,回收未使用的对象以避免内存泄漏和性能下降。本文深入介绍了JVM中的GC算法,包括串行、并行、CMS及G1等类型及其工作原理。选择合适的GC策略至关重要:小型应用适合串行收集器;大型应用或多核CPU环境推荐并行收集器或CMS;需减少停顿时间时,CMS是好选择;G1适用于大堆且对停顿时间敏感的应用。理解这些能帮助开发者优化程序性能和稳定性。
37 0
|
3月前
|
算法 Java
JVM自动内存管理之垃圾收集器
这篇文章是关于Java虚拟机(JVM)自动内存管理中的垃圾收集器的详细介绍。
|
4月前
|
监控 算法 Java
深入理解Java虚拟机:垃圾收集机制的演变与最佳实践
【7月更文挑战第14天】本文将带领读者穿梭于JVM的心脏——垃圾收集器,探索其设计哲学、实现原理和性能调优。我们将从早期简单的收集算法出发,逐步深入到现代高效的垃圾收集策略,并分享一些实用的调优技巧,帮助开发者在编写和维护Java应用时做出明智的决策。
51 3
|
4月前
|
算法 Java
Java面试题:列举并解释JVM中常见的垃圾收集器,并比较它们的优缺点
Java面试题:列举并解释JVM中常见的垃圾收集器,并比较它们的优缺点
95 3
|
4月前
|
Java UED
Java面试题:描述JVM中垃圾收集的Stop-The-World现象及其影响
Java面试题:描述JVM中垃圾收集的Stop-The-World现象及其影响
52 1

相关实验场景

更多