首页 > 其他分享 >JVM 的垃圾收集器

JVM 的垃圾收集器

时间:2023-12-30 10:37:11浏览次数:38  
标签:标记 收集器 GC 垃圾 JVM 线程 CMS


JVM 的垃圾收集器:Serial、ParNew 、 Parallel Scavenge、Serial Old、Parallel Old、CMS 、G1 。

 1. 概述

下图中垃圾收集器只要连线则表明垃圾收集器可以搭配使用。没有万能的收集器,具体应用选择合适的垃圾收集器。

JVM 的垃圾收集器_G1

2. Serial垃圾收集器

单线程收集器,用于新生代,这里的单线程指的是它在进行垃圾回收时暂停其他工作线程(STOP THE WORLD)

JVM 的垃圾收集器_G1_02

缺点:单线程,暂停其他工作线程,停顿过长时间难以忍受。

优点:简单高效(没有线程切换的开销),适用用户的桌面应用场景,停顿较短且不频繁。

2. ParNew垃圾收集器

Serial垃圾收集器的多线程版本,多条线程去进行垃圾收集。

JVM 的垃圾收集器_垃圾收集器_03

 多核 CPU 收集效果才会高于 Serial垃圾收集器。

它是 Server 场景下默认的新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合使用。

3.  Parallel Scavenge垃圾收集器

Parallel Scavenge垃圾收集器用于新生代 , 其目的是达到一个可控制的吞吐量,因此它被称为“吞吐量优先”收集器。

高吞吐量表明可以高效率地利用 CPU,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。交互多的场景需要停顿时间短,才能保证用户体验更好。

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

Parallel Scavenge 有两个控制停顿时间(-XX:MaxGCPauseMillis)和设置吞吐量大小(-XX:GCTimeRatio)的参数。

代价:降低停顿时间则会降低吞吐量,因为降低停顿时间意味着调低新生代内存,这样垃圾收集次数变的频繁。

Parallel Scavenge 可以自适应调节,打开 GC 自适应的调节策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例、晋升老年代对象年龄等细节参数了。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。

4. Serial Old 垃圾收集器

Serial垃圾收集器 的老年代版,使用标记-整理算法。

作为 CMS 的 预备方案,在 CMS 发生 Concurrent Mode Failure 的时候使用。

JVM 的垃圾收集器_CMS_04

5. Parallel Old垃圾收集器

Parallel Scavenge 垃圾收集器的老年代版本,使用多线程 和 标记-整理算法。

Parallel Scavenge+Parallel Old 适用于 注重吞吐量 和 CPU 资源敏感的 场合。

JVM 的垃圾收集器_G1_05

6. CMS 垃圾收集器

CMS 垃圾收集器,其目标是获取最短回收停顿时间,例如:B/S系统的服务端,重视响应速度,希望系统停顿时间最短。

CMS 收集器基于“标记-清除”算法实现,其运作过程:

(1)初始标记 (CMS initial mark)。标记和GC Roots 能直接关联到的对象,速度很快。

(2)并发标记(CMS concurrent mark)。耗时最长,可以和用户线程一起工作。

(3)重新标记(CMS remark)。修正并发标记期间因用户继续运作而导致标记产生变动的那一部分对象的标记记录。时间会稍长于初始标记,远短于并发标记。

(4)并发清除(CMS concurrent sweep)。耗时最长,可以和用户线程一起工作。

初始标记 和 重新标记是单线程。

JVM 的垃圾收集器_CMS_06

CMS 垃圾收集器的缺点:

(1)在并发阶段会占用一部分 CPU 资源,导致应用程序变慢,总吞吐量会降低。

如果CPU太少就会导致用户程序的执行速度大幅度降低,虚拟机为了处理这种情况,提出了 增量式并发收集器 i-CMS,即在并发标记-清理的时候让 GC 线程、用户线程交替运行,尽量减少 GC 线程的独占资源时间,用户程序的影响会降低,但是会导致垃圾收集过程变长。实践证明 i-CMS 效果一般。

(2)无法处理浮动垃圾,CMS并发清理阶段,程序任在运行,会不断产生新的垃圾(浮动垃圾),这些垃圾只能在下一次GC中才能清理,此时还需要保障有足够的内存空间给线程使用,因此CMS需要预留一部分空间,避免浮动垃圾过多,JDK5的默认设置中,CMS老年代使用了 68%的内存就会被激活(进行回收),JDK1.6 中,启动阈值已经提升到 92%,在 垃圾清理时如果预留的内存无法满足程序的需要,就会临时启用 Serial Old 收集器(暂停执行程序)。

可以通过修改 -XX:CMSInitiatingOccupancyFraction 的值来修改阈值。

(3)CMS 是基于标记-清除算法,会导致有大量空间碎片。

当无法找到足够大的连续空间分配当前对象,就会提前触发一次 Full GC(可以对内存碎片合并整理),内存整理无法并发,会导致停顿时间过长,可以通过XX:CMSFullGCsBeforeCompaction这个参数,设置执行多少次不对内存碎片合并整理的 Full GC , 跟着来一次内存碎片合并整理的Full GC。

7. G1 垃圾收集器

G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。

HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。

堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。

G1 (Garbage-First)的特点:

(1)并行和并发:充分利用多CPU、多核环境下的硬件优势,使用多CPU来缩短 STOP THE WORLD 的时间,部分其他收集器原本需要停顿Java线程执行的GC操作,G1收集器任然可以通过并发的方式让Java程序继续执行。

(2)分代收集:与其他收集器 一样,分代概念在G1中依然得以保留。

(3)空间整合。整体来看是标记整理算法,从局部来看(两个Region)上来看是基于“复制算法”。

(4)可预测的停顿。垃圾收集器的停顿时间不得超过一定时间。

G1 将整个 Java 堆划分为多个大小大的 独立区域 (Region),虽然还保留新生代和老年代的概念,新生代和老年代不再是物理隔离,他们都是一部分Region 。

G1 收集器之所以能建立可预测的停顿时间模型,因为它避免Java堆全区域的垃圾收集,G1 跟踪各个 Region 里面的垃圾堆积的价值大小,回收所获得的空间大小以及回收所需的经验值,在后台维护一个优先列表,每次根据允许的垃圾收集时间回收价值最大的Region(Garbage-First) 。

一个问题:Region不可能是孤立的,一个对象分配在一个Region 中,他会和在其他的Region 中的对象有引用关系,那么在做可达性判断的时候,还是需要扫描整个Java堆。

每个集合都有一个 Remembered SET。

如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:

初始标记, 并发标记,最终标记,筛选回收

初始标记:仅仅标记GC Roots能够直接关联到的对象。

并发标记:从GC Roots 对堆中的对象进行可达性分析。

最终标记是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行。

筛选回收首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。

JVM 的垃圾收集器_垃圾收集器_07

参考文献

  • 深入理解Java虚拟机:JVM高级特性与最佳实践 / 周志明著. —— 2 版 . —— 北京:机械工业出版社,2013.6 

标签:标记,收集器,GC,垃圾,JVM,线程,CMS
From: https://blog.51cto.com/xuxiangyang/9038451

相关文章

  • JVM-实战篇-GC调优
    1GC调优GC调优指的是对垃圾回收进行调优。GC调优的主要目标是避免由垃圾回收引起的程序性能下降。GC调优的核心分为三部分:通过JVM参数的设置;特定垃圾回收器的JVM参数的设置;解决由频繁的FULLGC引起的程序性能问题。GC调优没有唯一的标准答案,重点学习调优的工具和方法。......
  • 【GC】Java中常见的垃圾回收算法
    Java中常见的垃圾回收算法有以下几种:标记-清除算法(Mark-and-Sweep):该算法分为两个阶段,标记阶段和清除阶段。在标记阶段,垃圾回收器会遍历堆中的对象,并标记所有可达对象。在清除阶段,垃圾回收器会遍历堆中的对象,清除所有未被标记的对象。复制算法(Copying):该算法将堆分成两个区域......
  • 【Flink系列二十一】深入理解 JVM的类型加载约束,解决 Flink 类型加载冲突问题的通用方
    classByteArrayDeserializerisnotaninstanceoforg.apache.kafka.common.serialization.DeserializerDebuggingClassloading类似的XcannotbecasttoXexceptions如何理解这类异常?这类异常可以归纳为类型异常,按个人有限经验,现象分为两种常见情况:类型赋值检查:不能......
  • JVM-实战篇-内存调优
    1内存溢出和内存泄漏概念:内存泄漏:在Java中如果不在使用一个对象,但是该对象依然在GCROOT的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。内存泄漏绝大多数情况都是由堆内存泄漏引起的,所以后续没特殊说明讨论的均为堆内存泄漏。若持续发生内存泄漏,不管有......
  • 垃圾回收机制
    垃圾回收机制(GC)垃圾回收机制(简称GC)是Python解释器自带的一种机制专门用来回收不可用的变量值所占用的内存空间(在内存中,没有变量名指向的数据都是垃圾数据)(1)引用计数name='dhy'#'dhy'的引用计数就是1a=name#'dhy'的引用计数就是2(2)标记清除#一旦你的内存空间......
  • JVM的GC学习
    JVM的GC学习2023-12-28T17:20:25.182+0800:7.363:[FullGC(MetadataGCThreshold)[PSYoungGen:29067K->0K(13002752K)][ParOldGen:16K->26768K(16252928K)]29083K->26768K(29255680K),[Metaspace:20543K->20543K(1069056K)],0.0838171secs][Times:......
  • JVM虚拟机-基础篇1-初识JVM(一)
    1初识JVM1.1什么是JVM概念:JVM全称是JavaVirtualMachine,中文译名Java虚拟机。本质:JVM本质上是一个运行在计算机上的程序,它的职责是运行Java字节码文件。1.2JVM的功能 1)解释和运行对字节码文件中的指令,实时的解释成机器码,让计算机执行; 2)内存管理自动为对......
  • JVM跟踪类型参数
    JVM里有一系列的跟踪相关的参数,如下图(JAVA8) boolTraceBiasedLocking=false{product}boolTraceClassLoading=false{productrw}boolTrac......
  • 学一点关于JVM类加载的知识
    要研究类加载过程,我们先要知道关于Java处理代码的流程是怎么样的。第一步:编写源代码这一步是我们最熟悉的,就是我们在idea上写的业务代码,生成Example.java文件。publicclassExample{publicstaticvoidmain(String[]args){inta=10;intb......
  • 2、jvm虚拟机垃圾回收机制
    一、首先了解一下堆栈内存1、jvm内存结构  从上图可以看出,整个JVM内存是由栈内存、堆内存和永久代构成。年轻代(Newgeneration)=eden+s0+s1堆内存=年轻代+老年代(Oldgeneration)JDK1.8以前: JVM内存=栈内存+堆内存+永久代JDK1.8以后: 由元空间取代了永久代,......