chapter03_垃圾收集器与内存分配策略_5_垃圾收集器

本文详细介绍了Java中7种垃圾收集器的特点与应用场景,包括Serial、ParNew、ParallelScavenge、SerialOld、ParallelOld、CMS及G1收集器。探讨了它们之间的区别,如并行与并发操作、分代收集策略、空间整合方法以及如何实现可预测的停顿时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 垃圾收集器

    (1) 用于回收__新生代__:

    Serial:可以搭配CMS、Serial Old(MSC)使用

    ParNew:可以搭配CMS、Serial Old(MSC)使用

    Parallel Scavenge:可以搭配Parallel Old、Serial Old(MSC)使用

    (2) 用于回收__老年代__

    CMS(Concurrent Mark Sweep):可搭配Serial、ParNew、Serial Old(MSC)使用

    Serial Old(MSC):可搭配Serial、ParNew、Parallel Scavenge使用

    Parallel Old:可搭配Parallel Scavenge使用

    (3) 用于回收__新生代、老年代__

    G1(Garbage First)

  • 并行和并发

    并行:用户线程必须等待GC,但是GC过程本身是多线程的(用户停止扔垃圾,扫垃圾的清洁工有好几个同时扫)

    并发:用户线程和GC线程同时执行(用户一边扔垃圾,清洁工一边扫垃圾)

  • Serial收集器

    (1) __单线程__收集器,GC时必须停掉所有其他的工作线程,直到GC完毕

    (2) 新生代GC算法是__复制算法__,老年代GC算法是__标记-整理算法__,但是一般应用场景是Client模式下的新生代GC

    (3) 优点是__简单而高效__(因为会强制停掉其他工作线程),缺点是需要停顿

    (4) 适用场景就是新生代、内存较小的Client模式(因为停顿时间不会很长,同时简单高效)

    (5) 是Client模式下的__默认__新生代垃圾收集器

  • ParNew收集器

    (1) 和Serial收集器的实现几乎完全相同,区别就是使用__多线程__进行GC,但是也要停掉其他线程

    (2)新生代GC算法是__复制算法__,老年代GC算法是__标记-整理算法__,但是一般应用场景是Server模式下的新生代GC

    (3) 如果是单CPU环境,那么ParNew相比Serial并没有优势(甚至可能是劣势);但是多CPU环境下可以并行GC就有优势了

    (4) CMS是一款支持__并发__GC的老年代垃圾收集器,但是它只能和新生代收集器Serial、ParNew配合,所以如果是多CPU环境下就用ParNew

    (5) 综上,ParNew适合Server模式下的新生代收集

  • Parallel Scavenge收集器

    (1) 也是多线程并行GC(和ParNew一样),和ParNew的主要区别有两点:

    1° 关注的是__吞吐量__而非__停顿时间__

    2° 可以使用__自适应策略__调整参数

    (2) 停顿时间:每次GC时要暂停用户线程多长时间

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

    (3) 吞吐量和停顿时间常常是矛盾的:把新生代内存设小,那么GC一次的停顿时间肯定变小;但是意味着要经常GC,吞吐量就会下降

    (4) Parallel Scavenge收集器关注的是吞吐量更高,所以适合不需要太多交互、主要在后台计算、GC发生不频繁的场合

    (5) 打开 -XX:+UseAdaptiveSizePolicy参数以后,Parallel Scavange会根据系统运行情况,__自动__设置新生代大小、Eden与Survivor比例、晋升老年代对象大小等信息,无需手动设置

  • Serial Old收集器

    (1) 和Serial收集器实现方式基本一样,只不过用于Client模式下的老年代回收

    (2) 采取__标记-整理算法__

  • Parallel Old收集器

    (1) 是对应于Parallel Scavenge收集器的老年代收集版本

  • CMS(Concurrent Mark Sweep)收集器

    (1) 目标是获取最短GC停顿时间,因此采取了__并发__收集的思路

    (2) 用于__老年代__的收集,使用__标记-清除算法__

    (3) CMS收集器的工作过程分为4步:

    初始标记:要Stop the World,但是速度很快

    标记GC Roots可以直接关联的对象

    并发标记:不用Stop the World,和用户线程并发执行

    沿着GC Roots进行tracing,速度慢,但是是并发执行的

    重新标记:要Stop the World,速度比初始标记慢,但是比并发标记快

    修正并发标记期间因为用户程序修改导致标记错误的对象

    并发清除:不用Stop the World,和用户线程并发执行

    将死亡的对象清除掉,使用的是标记-清除算法

    (4) 优点:耗时长的2个步骤(并发标记、并发清除)都是和用户线程并发执行的,所以GC停顿时间短

    (5) 缺点

    对CPU资源非常敏感

    虽然可以并发执行,但是总要使用CPU来进行GC,所以CPU资源不足时会和用户线程竞争,影响用户线程的执行速度

    无法处理浮动垃圾

    由于并发清除的过程是一边在清理垃圾,一边用户线程还在产生垃圾,所以老年代要预留内存空间给清理时使用,不能像其他垃圾收集器一样等到老年代快满的时候再清理。

    这样诱发的问题是:老年代要设定一个阈值,空间占有率达到阈值后就要清理。如果这个阈值设的很小,那么要经常清理;如果阈值设的很大,可能在清理垃圾时导致用户产生的垃圾溢出了剩余空间,这时引发__“Concurrent Mode Failure”__。这个时候就要使用Serial Old来处理这种失败的情况进行GC,这也就是CMS要使用Serial Old的原因。

    内存空间碎片

    CMS采用标记-清除算法,会产生空间碎片。设置-XX:+UseCMSCompactAtFullCollection开关可以在发生Full GC时开启内存碎片的整理过程,但是停顿时间会变长

  • G1(Garbage First)收集器

    (1) 特点

    并行与并发

    多线程收集,并且GC中的很多步骤可以和用户线程并发执行

    分代收集

    使用G1收集器时,Java堆的内存布局和其他收集器很不一样:不再明确在物理上划分出新生代和老年代(一般来讲新生代的空间远小于老年代,而且GC更频繁),而是将堆划分成很多个__Region__,新生代和老年代都是一部分Region的集合,但是GC时的思想仍然是分代进行收集

    空间整合

    局部(两个Region之间)采用__复制算法__,整体采用__标记-整理算法__,避免了CMS收集器的内存空间碎片的问题

    可预测的停顿

    相比Parallel Scavenge/Parallel Old,G1最大的特点是可以根据用户设置的最大GC停顿时间完成GC

    (2) 步骤

    初始标记:和CMS的初始标记差不多

    并发标记:和CMS的并发标记差不多

    最终标记:和CMS的重新标记差不多

    筛选回收

    这个是G1收集器的特色部分,它首先对所有Region进行一下回收价值和回收时间的判断,然后根据用户指定的GC暂停时间,决定从哪个Region开始回收:在满足GC停顿时间的前提下,优先回收价值大的Region(所以叫Garbage First)

    (3) G1收集器最大的优势在于GC停顿时间可预测,而且它不需要和其他收集器配合,一个收集器完成新生代+老年代的收集,只不过内存中的结构变了

  • 总结一下以上的__7种__收集器:

    最简单的、也是默认的新生代收集器是__Serial__,它对应的老年代收集器是__Serial Old__;但是Serial/Serial Old的缺陷是单线程回收,于是出现了多线程并行回收的__ParNew__;另一个多线程并行回收的收集器__Parallel Scavenge__剑走偏锋,其他收集器关注点在停顿时间,而它关注点在吞吐量;曾经Parallel Scavenge没有对应的老年代收集器,Serial/ParNew/Parallel Scavenge都只能用Serial Old作为老年代收集器;后来__CMS__横空出世,做到了并行+并发回收老年代,然而CMS只支持Serial和ParNew,不支持Parallel Scavenge;终于__Parallel Old__诞生了,作为Parallel Scavenge对应的老年代收集器;最后,__G1__作为收集器最新成果,革新了Java堆内存的分布方式(Region块),可以一个收集器完成新生代+老年代的GC,并且还提供了可预测的GC时间

  • 垃圾收集器参数

    UseSerialGC:Client模式下的默认值,使用Serial+Serial Old

    UseParNewGC:使用ParNew+Serial Old

    UseConcMarkSweepGC:使用ParNew+CMS+Serial Old(Serial Old作为CMS回收失败后的备选)

    UseParallelGC:Server模式下的默认值,使用Parallel Scavenge+Parallel Old

    SurvivorRatio:Eden与Survivor的比值

    PretenureSizeThreshold:直接晋升到老年代的对象大小阈值

    MaxTenuringThreshold:晋升到老年代的对象年龄阈值

    ParallelGCThreads:并行GC时允许进行GC的线程数

    GCTimeRatio:使用Parallel Scavenge时允许的吞吐量(GC时间占总时间比例)

    MaxGCPauseMillis:使用G1时的最大停顿时间

    CMSInitiatingOccupancyFraction:使用CMS时老年代空间使用多少时触发GC

    UseCMSCompactAtFullCollection:使用CMS时完成GC后是否清理碎片

    CMSFullGCsBeforeCompaction:使用CMS时进行几次GC后来一次碎片清理

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值