Java 捡垃圾利器

article/2025/7/1 19:24:44

文章目录

      • 垃圾收集器
        • Serial
          • 优点
          • 使用场景
        • ParNew
          • 使用场景
          • 配合使用
            • CMS
            • G1
        • Parallel Scavenge
          • 使用场景
          • 参数
        • Serial Old
        • Parallel Old
        • CMS
          • 流程
          • 优点
          • 缺点
        • G1
          • 概述
          • 主要特征
          • 内存分布
          • 回收
          • 定位
          • 问题与解决方案
          • 与 CMS
        • 小结
        • 拓展阅读
        • 参考资料

垃圾收集器

收集算法是内存回收的方法论,垃圾收集器就是内存回收的实践者。

在这里插入图片描述

以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。

在 JDK 8 时将 Serial+CMS 、 ParNew+Serial Old 声明废弃,JDK 9 中完全取消。

  • 单线程与多线程:单线程指的是垃圾收集器只使用一个线程,而多线程使用多个线程;
  • 并行(Parallel):同一时间有多条垃圾收集器线程在协同工作,默认此时的用户线程是处于等待状态
  • 并发(Concurrent):垃圾收集器和用户程序同时执行。会影响吞吐率。除了 CMS 和 G1 之外,其它垃圾收集器都是以并行的方式执行。

Serial

在这里插入图片描述

单线程工作的收集器使用复制算法,仅使用一个处理器或一条收集线程去完成垃圾收集工作,在进行垃圾收集时,必须暂停其他所有工作线程,直到收集结束

优点

与其他单线程收集器相比更加的简单高效

  • 内存资源受限的环境中,它是额外内存消耗最小的。
  • 在单个 CPU 环境下,由于没有线程交互的开销,因此拥有最高的单线程收集效率。
使用场景

所以它是 Client 场景下的默认新生代收集器,因为在该场景下内存一般来说不会很大。它收集一两百兆垃圾的停顿时间可以控制在一百多毫秒以内,只要不是太频繁,这点停顿时间是可以接受的。

ParNew

在这里插入图片描述

它是 Serial 收集器的多线程版本,使用复制算法。除了同时使用多条线程外,其他的行为包括控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与 Serial 完全一致。

使用场景

服务端模式下的虚拟机,JDK 7之前遗留系统中首选的新生代收集器除了Serial收集器外,只有它能与 CMS 收集器配合使用。

在单核处理器中性能比 Serial 差,由于存在线程切换的开销,在超线程中性能也比 Serial 差。

默认开启的线程等于CPU核心数量,使用-XX:ParallelGCThreads 现在垃圾收集的线程数。

配合使用
CMS

CMS 是第一款并发收集器一般针对老年代使用。使用 -XX:+UseConcMarkSweepGC激活。在 JDK 5使用时新生代选择 ParNew 或 Serial 收集器。

ParNew 是CMS的默认新生代收集器,使用-XX:+/-UseParNewGC 指定或禁用。

G1

G1是面向全堆的收集器,不需要配合其他新生代收集器工作。

JDK 9 之后,使用 G1 取代 CMS + ParNew,且 ParNew 已融合进 CMS 中。

Parallel Scavenge

在这里插入图片描述

新生代收集器,基于标记-复制算法,能并行收集的多线程收集器。

使用场景

其它收集器目标是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是达到一个可控制的吞吐量,因此它被称为**“吞吐量优先”**收集器。

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

  • 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。

  • 而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。

缩短停顿时间是以牺牲吞吐量和新生代空间来换取的:新生代空间变小,垃圾回收变得频繁,导致吞吐量下降。

参数
  • -XX: MaxGCPauseMillis:允许一个大于 0 的毫秒数,收集器尽力保证内存回收时间不超过设定值。

  • -XX: GCTimeRatio:大于 0 小于 100 的整数,表示垃圾收集时间占总时间的比例,相当于吞吐率的倒数。

  • -XX: +UseAdaptiveSizePolicy:

    • 开启 GC 自适应的调节策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 区的比例(-XX: SurviorRatio)、晋升老年代对象大小(-XX:PretenureSizeThreshold)等细节参数了。
    • 虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
    • 只需要设置基本的内存数据(-Xmx设置最大堆),然后设置虚拟机的优化目标。
    • 自适应调节策略是区别于 ParNew 的重要特性。

Serial Old

在这里插入图片描述

Serial 收集器的老年代版本,使用标记-整理算法,也是给 Client 场景下的虚拟机使用。

如果用在 Server 场景下,它有两大用途:

  • 在 JDK 1.5 以及之前版本(Parallel Old 诞生以前)中与 Parallel Scavenge 收集器搭配使用。
  • 作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

Parallel Old

在这里插入图片描述

Parallel Scavenge 收集器的老年代版本,使用标记-整理算法。

注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。

CMS

在这里插入图片描述

CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。针对老年代的以获取最短回收停顿时间为目标的收集器。

流程
  • 初始标记:仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿
  • 并发标记:进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿
  • 重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿
  • 并发清除:清理标记好的对象,不需要移动存活对象。不需要停顿

在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,总体来说 CMS 内存回收过程是与用户线程一起并发执行的。

优点

并发收集、低停顿。

缺点
  1. 低停顿时间是以牺牲吞吐量为代价的,导致 CPU 利用率不够高。
  • 占用了一部分线程而导致应用程序变慢,降低总吞吐率。默认启动的线程数是 (处理器核心数量+3) / 4,核心数在4个或以上时,只占用不超过25%,核心越多影响越小。

  • 处理器负载高时,就可能导致用户程序的执行速度忽然大幅降低。

  • “增量式并发收集器(i-CMS)”:在并发标记、清理的时候让收集器线程、用户线程交替运行。

  1. 无法处理浮动垃圾,可能出现 Concurrent Mode Failure,从而导致一次 Full GC。
  • 浮动垃圾是指并发清除阶段由于用户线程继续运行而产生的垃圾,这部分垃圾只能到下一次 GC 时才能进行回收。由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure,这时虚拟机将冻结用户线程的执行,临时启用 Serial Old 来替代 CMS,从“标记-清除”转为“标记-整理”,这样会使得停顿时间加长。
  • JDK 5:当老年代使用了 68% 的空间后就会被激活,JKD 6:阈值默认提升至 92%。
  • -XX: CMSInitiatingOccupancyFraction值来提高CMS的出发百分比,降低内存回收频率,获取更好的性能。设置得太高容易导致大量的并发失败产生,性能反而降低。
  1. 标记 - 清除算法导致的空间碎片,往往出现老年代空间剩余,但无法找到足够大连续空间来分配当前对象,不得不提前触发另一次 Full GC。
  • -XX:+UseCMS-CompactAtFullCollection:用于在 CMS 收集器不得不进行Full GC时开启内存碎片的合并整理过程,使用一次“标记-整理”算法。此过程需要移动存活对象,所以无法并发。JDK 9开始废弃。
  • -XX:CMSFullGCsBefore-Compaction:执行一定次数不整理空间 Full GC 后,执行一次整理空间的 Full GC,默认为每次都整理。JDK 9开始废弃。
  • 让虚拟机平时使用“标记-清除”算法,但内存碎片化程度已经大到影响内存分配时,使用一次“标记-整理”算法,如 CMS 收集器。
    在这里插入图片描述

G1

概述

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

堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1是面向局部收集的设计思路和基于 Region 的内存布局形式,可以直接对新生代和老年代一起回收。

主要特征

停顿时间模型

能够支持指定在一个长度为 M 毫秒的时间片段内,消耗在垃圾收集器上的时间大概率不超过 N 毫秒这样的目标。

使用 Mixed GC 模式支持此模型的实现,面向堆内存任何部分来组成回收集(Collection Set)进行回收,标准为哪块内存中存放的垃圾数量最多,回收收益最大

-XX: MaxGCPauseMillis,默认为 200 毫秒,如果停顿目标时间太短,则可能会因为收集速度跟不上分配速度而导致垃圾堆积最终引发 Full GC。

内存分布

在这里插入图片描述

在这里插入图片描述

遵循分代收集理论设计,G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。

每一个 Region 都可以是新生代的 Eden 空间、Survivor 空间或者老年代空间,G1 收集器会针对不同角色的 Region 采用不同的收集策略。

Humongous 区域存放大对象,默认为超过了 Region 容量一半的对象即为大对象,该阈值可通过 -XX:G1HeapRegionSize 设定,范围为 1MD ~ 32MB,且为 2 的 N 次幂。

如果对象比 Humongous 还大,则将之存放在连续的 Humongous 中,因为该区域存放的对象很大,频繁回收引起的消耗会很大,所以 Humongous Region 应作为老年代的一部分。

回收

每次收集的内存空间都为 Region 大小的整数倍。

通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集停顿时间,优先回收价值最大的 Region。

在这里插入图片描述

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

  • 初始标记标记 GC Roots 能直接关联到的对象并修改 TAMS 指针的值,使得下一阶段用户线程并发运行时能正确地在可用的 Region 中分配对象。在进行 Minor GC 时同步完成停顿操作耗时较短
  • 并发标记并发操作,进行可达性分析,扫描整个堆里的对象图,耗时较长
  • 最终标记:为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程的 Remembered Set Logs 里面,最终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中。这阶段需要停顿线程,但是可并行执行
  • 筛选回收:首先对各个 Region 中的回收价值和成本进行排序,根据用户所期望的 GC 停顿时间来制定回收计划,最后把决定要回收的 Region 的存活对象复制到空的 Region 中,再清理整个旧 Region 的全部空间,涉及对象移动,必须暂停用户线程。此阶段其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region,时间是用户可控制的,而且停顿用户线程将大幅度提高收集效率。此阶段占停顿期望值的大部分。
定位

在 JDK 9 时宣告取代 Parallel Scavenge 和 Parallel Old 组合,成为服务端模式下的默认垃圾收集器, CMS 被声明为不推荐使用的收集器。

除了并发标记外,其余阶段都需要完全暂停用户线程,追求的是在延迟可控的情况下获得尽可能高的吞吐量。

问题与解决方案
  • 如何解决跨 Region 引用对象
    1. 每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
      • Key 是 Region 的起始地址, Value 是存储卡表的索引号的集合。
      • 双向卡表:记录“我指向谁”以及“谁指向我”。比传统卡表占用更多内存。
  • 并发标记阶段如何保证收集线程与用户线程互不干扰的运行
    1. 解决用户线程改变对象引用关系时,保证其不能打破原本的对象图结构,导致标记结果出错
      • CMS 采用增量更新算法实现,G1 采用原始快照(SATB)实现。
    2. 回收过程中新创建对象的内存分配
      • 每个 Region 都有两个 TAMS(Top at Mark Start)指针,在 Region 内部有一部分内存用于并发回收过程中的新对象分配,新分配的对象地址都必须要在这两个指针位置以上。这个位置的对象默认存活,即不会被回收。
      • 内存回收速度赶不上内存分配速度时,G1 会冻结用户线程,导致 Full GC 而产生长时间 “Stop The World”。
  • 如何建立可靠的停顿预测模型
    1. 使用 -XX: MaxGCPauseMillis指定停顿的期望值。
    2. 衰减均值
      • 通过 Region 的回收耗时、记忆集里的脏卡数量等可测量的步骤花费的成本,算出平均值、标准偏差、置信度等统计信息。
      • 平均值代表整体平均状态,衰减平均值代表最近的平均状态。统计状态越新越能绝对其回收价值。
      • 通过该值可预测在期望停顿时间下获得的最高收益。
与 CMS
  • 算法:CMS 使用 标记-整理。G1 在局部上因为使用 标记-复制,在整体上使用 标记-整理,G1 运作期间不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。
  • 消耗:G1 垃圾收集产生的内存占用以及程序运行的额外执行负载都比 CMS 高。
    • 内存占用:G1 的卡表实现更为复杂,老年代和新生代都有卡表。CMS 只有老年代有卡表,记录老年代到新生代的引用,但是当 CMS 发生 Old GC 时,要把整个新生代作为 GC Roots 扫描。
    • 执行负载:CMS 使用写后屏障更行维护卡表。G1 除了使用写后屏障来进行同样的操作,为了实现原始快照搜索 SATB 算法,还需要使用写前屏障来跟踪并发时的指针变化情况。
      • 原始快照搜索 STAB:减少并发标记和重新标记阶段的消耗,减少停顿时间,但会因为跟踪引用变化而产生额外负担。
      • 写时屏障:CMS 直接同步。G1为消息队列结果,把写前屏障和写后屏障中要做的事情都放到队列,再进行异步处理。
  • 使用场景:小内存上使用 CMS,大内存上使用 G1,一般的界限为 6GB ~ 8GB。

小结

  • **停顿状态:**浅色为必须挂起用户线程,深色为用户线程与垃圾收集线程并发。

在这里插入图片描述

  • 性能指标:内存占用、吞吐量、延迟。随着硬件规格的提升,内存占用和吞吐量不再是瓶颈,延迟才是最需要优化的地方。内存越大,延迟可能就越高,降低延迟就是缩短 Stop The World 的时间。
    • CMS 使用增量更新,G1 使用原始快照的方式实现标记阶段的并发,不会因为堆内存变大而导致停顿时间增长。
    • CMS 使用标记-清除算法,会积累内存碎片,碎片到达一定量的时候会引发一次 Full GC,这个过程会停顿用户线程。
    • G1 的回收粒度更小,所需要整理的内存就越少,所停顿的时间就越短。

拓展阅读

Java 捡垃圾黑科技

关于 Java 捡垃圾那些事


⭐️ 如果对你有帮助,请点个赞👍

参考资料

《深入理解Java虚拟机-第三版》
cyc 2018
JavaGuide
《Java虚拟机原理图解》4.JVM机器指令集


http://chatgpt.dhexx.cn/article/2tYs8NNt.shtml

相关文章

垃圾回收站

【冒泡排序】c实现冒泡排序代码 【冒泡排序】c实现冒泡排序代码 【冒泡排序】c实现冒泡排序代码固态激光雷达 转载自 yangchuang93 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 冒泡排序的基…

labweek8

实验报告 实验内容 进程间通信—消息机制。 (1) 编译运行课件 Lecture 09 例程代码:Algorithms 9-1 ~ 9-2. (2) 修改代码,观察在 msgsnd 和 msgrcv 并发执行情况下消息队列的变化情况。 (3) 仿照 alg.8-4~8-6,编制基于 POSIX API 的进程间…

常见垃圾回收器

CMS和G1是最重要的 新生代一般采用标记复制,老年代一般采用标记整理算法 Serial:垃圾回收线程只有一个,而且垃圾回收线程工作的时候其他用户线程要停下来 Parnew:Serial的多线程版本,有多个垃圾回收线程,垃…

垃圾回收(一)

文章目录 1. 确定哪些对象还“存活”,哪些已经“死去”1.1 引用计数算法1.2 可达性分析算法1.3 引用 2.垃圾回收算法2.1 分代收集理论跨代引用 2.2 标记-清除算法2.3 标记-复制法2.4 标记-整理算法 垃圾收集需要完成的三件事: 哪些内存需要回收&#xff…

python 垃圾箱-垃圾回收

前戏 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那什么样的变量值…

纪念第一届cccc天梯赛

来一篇迟到的文章 先来爆一下战绩吧:SDUT,学校排名全国第六获金,山东省冠军。学校一共三支队伍,学长们一支最强的队获一等奖,剩下的两支二等奖。 战绩总体来看还不错吧,离不开我们每一个队员和老师们的努…

2021 CCCC天梯赛补题

前言不想看请直接跳过~~~~ 前言检讨:天梯赛我拉垮了,我拖了队伍后腿,我有罪。 分析原因,首先是前一个星期训练量不够,没有跟上队友训练的进度,一些基础的STL的…

2021年CCCC天梯赛 【部分题题解】

天梯赛有三个level,第一个level基本就是语法题,第二个level是基础算法和STL库的一些应用。 第三个level就是一些难的算法。 L3的题都不是太会,有思路但是写不出来。 目录 L1人与神两小时学完C语言强迫症降价提醒机器人大笨钟的心情吉老师的回…

2021年CCCC天梯赛L3 还原文件题解

题目如下 一份重要文件被撕成两半,其中一半还被送进了碎纸机。 我们将碎纸机里找到的纸条进行编号,如图 1 所示。然后根据断口的折线形状跟没有切碎的半张纸进行匹配,最后还原成图 2 的样子。 要求你输出还原后纸条的正确拼接顺序。 图 1…

2020CCCC天梯赛补题记录

目录 总结补题L2-035 完全二叉树的层序遍历 (25分)L2-036 网红点打卡攻略 (25分)L3-025 那就别担心了 (30分)28分版本:30分版本(记忆化搜索) 总结 1.口罩那题打完就只剩三十分钟了,之后卡在了完全二叉树的层序遍历那题,就没有再敢往后看&…

2021 CCCC天梯赛L1补题

前言 这次天梯赛表现没有达到预期,L1的分没有拿全,L2有2题没考虑完全,总之很愧疚拖了队友后腿。今天先补上L1没拿满分的题。 L1补题 前言L1-078 吉老师的回归输入样例1输出样例1输入样例2输出样例2 思路代码实现 L1-080 乘法口诀数列输入样例…

CCCC天梯赛 L2-037 包装机

CCCC天梯赛 L2-037 包装机 一种自动包装机的结构如图 1 所示。 首先机器中有 N 条轨道,放置了一些物品。 轨道下面有一个筐。 当某条轨道的按钮被按下时,活塞向左推动,将轨道尽头的一件物品推落筐中。 当 0 号按钮被按下时,机械手…

2022年CCCC天梯赛题解

L1-1今天我要赢 原题链接 代码 #include<bits/stdc.h> #define int long long #define rep(i, a, b) for(int ia;i<b;i) #define Rep(i, a, b) for(int ia;i>b;--i) using namespace std; const int N 10005; inline int read(){int s0,w1;char chgetchar();wh…

第八届cccc团体程序设计天梯赛——个人参赛总结——无代码纯粹的参赛总结

第八届cccc团体程序设计天梯赛——个人参赛总结——无代码纯粹的参赛总结 目录 第八届cccc团体程序设计天梯赛——个人参赛总结——无代码纯粹的参赛总结引言~介绍一下cccc天梯赛&#xff08;选读&#xff09;开篇介绍&#xff08;以下是个人经历部分的分享&#xff09;赛前准备…

怎样合理地营销推广App和吸引住大量的客户提高转化?

开发App进行后&#xff0c;一切应用软件都必须营销推广&#xff0c;尤其是在互联网技术收益消退的情况下&#xff0c;怎样合理地营销推广和吸引住大量的客户总流量早已变成很多互联网公司最关注的难题。 APP运用引流方法工作中看上去很繁杂&#xff0c;难度系数很大&#xff0…

APP在应用市场内该如何做推广

苹果应用商城的自然流量都是通过精品推荐&#xff0c;畅销排行榜和搜索来获取的&#xff0c;此外&#xff0c;应用名称、副标题、应用截图视频、应用描述、用户评论、下载量、用户留存率还有曝光量&#xff0c;这些都是影响ASO优化的关键因素。 为了防止一些应用堆砌热词&…

App推广拉新的6大方式,你都玩得转吗?

中国的互联网发展至今,除了App以外,公众号,小程序在微信生态中的独领风骚,快应用也像“太子”一样在11家国产手机厂商的簇拥下茁壮成长,而百度的百家号、头条的头条号、阿里的大鱼号也已经和微信开始“正面刚”。App这种古老的产品形态,正受到市场的不断冲击。 根据Quest…

什么是App推广技术?

在移动互联网红利消失殆尽、市场竞争日趋激烈的背景下,App的推广越来越难了,如何去有效的进行推广,吸引更多的用户流量,成为了众多互联网企业最为关注的问题。 而App 推广技术指的就是通过一些技术的方式来提高 App 推广效率,帮助众多互联网企业,解决 App 推广难的问题。…

如何正确推广App,实现高转化用户。

个性化深度链接技术的应用。深度链接使网页和App两者串联起来&#xff0c;减少了转换漏斗中的损失。再加上深度链接不仅能改善潜在用户的转化&#xff0c;对沉睡用户的唤醒同样也能发挥关键作用。 类型不含深度链接使用深度链接携带参数首页商品的id号&#xff0c;房间号&…

电商App:提高推广转化率的几件事

双十一将至&#xff0c;电商App获客却越来越难&#xff0c;成本越来越高。想要做好用户拉新并转化为有效用户&#xff0c;这里整理了一套拉新留存方法论&#xff0c;可以参考使用。 一、找准目标用户 首先明确用户群定位&#xff0c;可以从年龄范围、职业范围、性别、地域、消…