JVM(四)垃圾回收

1 垃圾标记

1.2 引用计数算法:

image

1.2.1 示例

image
image

1.2.2 弊端

存在循环引用的问题
image
image

1.2 可达性分析算法:

image
image

GC root包含哪些?
image

2 GC算法

2.1 标记-清除算法

从gc root遍历所有对象,标记可达对象,即存活对象,然后再遍历所有的对象(过程为下图的蓝色横线),清除垃圾对象。
image
image

2.1.1 标记清除算法缺点

效率不高,因为需要从头遍历。清除的意思是,把上图黑色的垃圾对象的内存地址保存在空闲列表,下次有新的对象时,将黑色的块覆盖了,并不是将黑色块置空。
image

2.2 复制算法

准备B区,A区开始,从GC roots开始遍历,遍历到可达的对象复制到B区,S1区和S2区就用到了复制算法,S区的对象大多朝生夕死。
image
image

  • 复制算法优点:没有标记清除过程,高效,复制后保证空间的连续性,没有碎片问题。
  • 复制算法缺点:需要内存空间大,复制后需要维护新的引用关系。而且如果系统存活的对象多和垃圾少,需要复制很多对象,会使效率低。因此适用于新生代。

2.3 标记压缩算法

image
image
image

3 分代收集

分代收集是JVM垃圾回收的‌基础架构‌,其核心思想源于“弱代假说”:‌绝大多数对象朝生夕灭,少数对象长期存活‌。

3.1 实现方式‌

将Java堆划分为两个主要区域:
1、新生代(Young Generation)‌:存放新创建的对象,存活率低,回收频繁。
采用‌复制算法‌:将存活对象复制到另一块Survivor区,清空原区,效率高、无碎片。
默认比例:Eden : Survivor1 : Survivor2 = 8 : 1 : 1。

2、老年代(Old Generation)‌:存放熬过多次Minor GC的对象,存活率高。
采用‌标记-清除‌或‌标记-整理‌算法,避免频繁复制开销。

4 垃圾回收的相关知识点

4.1 内存溢出与内存泄漏

image

4.2 GC的串行、并发、并行:

GC的三种“工作模式”‌:

  • 串行(Serial)‌‌:单线程‌执行GC,暂停所有应用线程(Stop-The-World)
  • 并行(Parallel)‌:多线程并行‌执行GC,仍暂停应用线程
  • 并发(Concurrent)‌‌:GC线程与应用线程同时运行‌,不完全暂停应用
    image
    image

4.3

4.3.1 STW(STOP THE WORLD)

image
image

4.3.2 安全点与安全区域:

4.3.2.1 安全点

image

  • 实现机制‌:采用‌主动式中断(Voluntary Suspension)‌
    JVM设置一个全局“安全点标志”。
    所有Java线程在执行到安全点时,‌主动轮询‌该标志。
    若发现标志为真,线程‌自行挂起‌,等待GC等操作完成。

  • 比如,线程执行到方法调用指令,就会停下来。

4.3.2.1 安全区域

当线程处于‌非运行状态‌(如 Thread.sleep()、Object.wait()、I/O阻塞、JNI调用)时,它‌无法主动执行代码‌,也就无法到达安全点。此时,安全点机制失效。

解决方案‌:引入‌安全区域‌
线程进入一段‌引用关系不会发生变化‌的代码段(如阻塞系统调用、JNI本地方法)时,会‌主动声明进入安全区域‌。
在此区域内,JVM‌无需等待该线程到达安全点‌,可直接将其视为“已暂停”。
当线程准备离开安全区域时,必须‌检查GC是否已完成‌:
若已完成 → 直接继续执行。
若未完成 → ‌阻塞等待‌,直到GC结束信号到达。

补充说明:
image

4.4 终结引用

5 垃圾回收器

5.1 GC的性能指标

重点看标红的三个,这三个不可能都满足。
image
image

5.1.1 吞吐量

image

5.1.2 暂停时间

image

5.1.3 示例

image

  • 注重吞吐量:(200ms+200ms)/6000ms,总暂停400ms
  • 主动低延迟:每次暂停100ms,总暂停500ms

5.1.4

image

5.2 垃圾回收器组合

image

5.3 Serial回收器

概述:单线程、串行执行‌的收集器。年轻代用Serial,老年代用Serial Old。仅使用一个CPU核心‌,所有GC操作(标记、清除、复制)均由单线程完成,执行垃圾回收时,暂停所有应用线程‌(Stop-The-World),直到GC结束才恢复程序运行;新生代使用‌复制算法‌(Copying),老年代使用‌标记-整理算法‌(Mark-Compact)。

  • 使用 -XX:+UseSerialGC 显式启用的JVM

image

图示:

image

5.4 ParNew回收器

并行回收,该回收器就是Serial回收器的并行版本,STW时间较短
image

图示,新生代使用ParNew,老年代使用Serial Old

image

5.5 CMS回收器

CMS 专为对响应时间敏感的应用(如 Web 服务)设计,通过并发执行垃圾回收线程与用户线程,显著减少 STW 停顿。其采用‌标记-清除算法‌。

5.5.1 CMS工作原理:

  • 初始标记(STW)‌,仅仅标记GC Roots直接引用的对象(如栈帧变量、静态字段)(如栈引用、静态变量)。停顿时间极短
  • 并发标记,从初始标记阶段标记好的的对象出发,遍历整个对象图,标记所有可达对象
  • 重新标记(STW)‌,由于并发标记阶段,用户线程是不停的、运行着的,这时可能会出现以下的情形,一,有的对象会创建出来,然后很快成为垃圾,,二,有的标记好的对象是存活的,用户贤臣将其变为不存活。因此需要重新标记。
  • 并发清除,清理垃圾对象。

image

5.5.2 CMS缺点

  • 内存碎片:使用“标记-清除”算法,不进行压缩,长期运行易产生碎片,可能导致Full GC 。可以使用以下参数来进行压缩,-XX:CMSFullGCsBeforeCompaction=N‌(默认值0),意为,每经历N次Full GC‌后,才执行一次碎片压缩

  • 退化问题,若老年代空间不足或回收速度跟不上分配速度,会退化使用Serial Old进行Full GC,导致长时间停顿 。

  • 浮动垃圾,并发清除期间用户线程仍可分配对象,这部分垃圾无法回收

  • CPU资源占用高‌:并发阶段需占用CPU资源,在CPU较少时影响明显。比如2核,1个核用来跑并发处理,1个核跑用户线程。

5.6 Parallel Scavenge‌ 和 ‌Parallel Old‌

Parallel Scavenge‌ 是‌新生代‌的垃圾回收器,采用‌复制算法‌,专注于‌高吞吐量‌(Throughput)。
Parallel Old‌ 是‌老年代‌的垃圾回收器,采用‌标记-整理算法‌,是 Parallel Scavenge 的老年代搭档。

java8默认的回收器。

高吞吐量

  • 适合后台计算和批处理任务‌
    • 数据批处理作业‌(如日志分析、报表生成)
    • 科学计算或模拟任务‌
    • 任务执行时间较长,允许偶尔的较长 GC 停顿,更关注整体任务完成时间,而非单次请求的响应延迟,例如:视频转码、大规模数据导入、定时统计任务等

5.6.1 原理之多线程并行处理

image

5.6.2 内存自适应

自适应调整
1、自动化调优‌:根据应用的实际运行情况,动态调整新生代、老年代的大小及晋升阈值等关键参数。

2、平衡吞吐量与停顿时间‌:在保证高吞吐量的前提下,尽可能控制垃圾回收的停顿时间。

5.6.3 自适应调整的工作原理‌

1、监控运行时数据‌
Parallel Scavenge 会持续收集垃圾回收过程中的关键指标,例如:对象分配速率、对象存活时间分布、每次 GC 的停顿时间、堆内存的使用效率。

2、基于监控数据,自动调整以下参数:
新生代与老年代比例‌:根据对象晋升模式优化内存划分。

晋升阈值‌:控制对象从新生代进入老年代的条件。

堆大小扩展/收缩‌:根据负载变化调整总堆容量。

2.3、反馈式优化‌
通过多次 GC 周期的数据反馈,逐步逼近最优配置,适应应用不同阶段的内存使用特征。

5.6.4参数

1、启用 Parallel Scavenge + Parallel Old 组合
-XX:+UseParallelGC 或-XX:+UseParallelOldGC

2、设置最大暂停时间
-XX:MaxGCPauseMillis:n ,设置每次垃圾回收时的最大停顿毫秒数

3、设置吞吐量
-XX:GCTimeRatio:n ,设置吞吐量为n,即=n/(n+1)。如n为99,就是99%的吞吐量

4、启用自适应调节策略。默认开启
-XX:+UseAdaptiveSizePolicy‌

  • 最大暂停时间和吞吐量要平衡使用。比如极端情况下,最大暂停设置为1ms,吞吐量设置为99%,垃圾回收器很可能是办不到的。

5.7 G1收集器

5.7.1 介绍

1、分区Region:化整为零
image

2、H区举例,区域设置为4MB,有一个对象是7MB,那么就放H区。连续的H区,比如下图中占了三个格子的H区
image
image

3、某个E区被整个回收后,可以充当O区,但是某个区不能既是E区又是O区
image

4、优点
image

5.7.2 流程概述

image

5.7.3 执行流程之年轻代回收

image
image
image

  • 会导致 Stop-The-World(STW)

选择某些区域的依据
image

  • 最多只能回收4个,因为5个的话,可能会超过200ms。要考虑余量

image

  • 5.1 回收eden区与s区,存活的复制到另一个s区
    image

  • 5.2 达到阈值的晋升老年代,没有达到的复制到另一个s区
    image

image

5.7.4 执行流程之混合回收

image

  • 7.1 混合回收 (MixedGC)
    image

5.7.4 混合回收的过程

并发标记,从GC Roots出发,遍历存活的对象,并且标记

最终标记,漏标的对象是,并发标记时没有标记的对象(不存活的),因为被引用的关系导致存活了,要标记上;用户线程执行中,可能会新建对象,不理会,下次GC再处理;用户线程执行中,可能有的对象会不再存活了,也不理会,下次GC再处理。

并发复制清理,这个过程中,对于老年代来说,会选择存活度低的区域来回收(G1名字的由来)。存活度,比如有两个老年代区,第一个区100个对象存活1个(低存活度),第二个100个对象存活99个。这样会释放更多的内存。
image

混合回收图示:红色为存活度低的区域。s是survivor区,O是Old区
image

注意:
image

image

posted @ 2026-01-27 16:38  dvdhellohaha  阅读(26)  评论(0)    收藏  举报