Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾收集器
文章目录
- 垃圾回收机制
- Stop-the-World
- 垃圾收集器
- 垃圾收集器分类
- Serial 收集器
- Serial Old 收集器
- ParNew 收集器
- Parallel Scavenge 收集器
- Parallel Old 收集器
- CMS 收集器
- CMS 收集器缺点
- G1 收集器
- G1 收集器特点
- G1 收集器的分代理念
- G1 收集器运作过程
垃圾回收机制
垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
Stop-the-World
"Stop The World"是 Java 垃圾收集中的一个重要概念。在垃圾收集过程中,JVM 会暂停所有的用户线程,这种暂停被称为"Stop The World"事件。这么做的主要原因是为了防止在垃圾收集过程中,用户线程修改了堆中的对象,导致垃圾收集器无法准确地收集垃圾。
"Stop The World"事件会对 Java 应用的性能产生影响。如果停顿时间过长,就会导致应用的响应时间变长,对于对实时性要求较高的应用,如交易系统、游戏服务器等,这种情况是不能接受的。
因此,在选择和调优垃圾收集器时,需要考虑其停顿时间。Java 中的一些垃圾收集器,如 G1 和 ZGC(下文有详细讲解),都会尽可能地减少了"Stop The World"的时间,通过并发的垃圾收集,提高应用的响应性能。
垃圾收集器
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。Java 垃圾收集器(Garbage Collector, GC)是 Java 虚拟机(JVM)的一部分,它自动管理内存,回收不再使用的对象所占用的内存空间。这有助于防止内存泄漏,并且使得开发人员可以更专注于业务逻辑的编写而不是内存管理。
没有万能的垃圾收集器,只有根据具体应用场景选择适合自己的垃圾收集器。垃圾收集器是垃圾回收算法(如引用计数法、标记清除法、标记整理法、复制算法等)的具体实现。它的主要任务是识别并回收那些不再被程序使用的对象所占用的内存空间,从而避免内存泄漏和内存溢出的问题。
垃圾收集器分类
就目前来说,JVM 的垃圾收集器主要分为两大类:分代收集器和分区收集器,分代收集器的代表是 CMS,分区收集器的代表是 G1 和 ZGC
JDK 默认垃圾收集器(使用 java -XX:+PrintCommandLineFlags -version 命令查看):
- JDK 8:
Parallel Scavenge(新生代)+Parallel Old(老年代) - JDK 9 ~ JDK20:
G1

Serial 收集器
Serial(串行)收集器是最基本、历史最悠久的垃圾收集器。此收集器是一个单线程收集器了。
它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “STW Stop The World” ),直到它收集结束。
新生代采用标记-复制算法,老年代采用标记-整理算法。

Serial 收集器简单而高效(与其他收集器的单线程相比)。由于没有线程交互的开销,自然可以获得很高的单线程收集效率,对于运行在 Client 模式下的虚拟机来说是个不错的选择
Serial Old 收集器
Serial 收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在 JDK1.5 以及以前的版本中与 Parallel Scavenge 收集器搭配使用,另一种用途是作为 CMS 收集器的后备方案。
![![[Pasted image 20231011233428.png]]](https://i-blog.csdnimg.cn/direct/0474536063004f70a30292009dc5250a.png)
ParNew 收集器
ParNew 收集器是 Serial 收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和 Serial 收集器完全一样。
新生代采用标记-复制算法,老年代采用标记-整理算法。
![![[Pasted image 20231011233540.png]]](https://i-blog.csdnimg.cn/direct/add181f8832c48c9998060e3be1a8649.png)
并行和并发概念补充:
-
并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
-
并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器运行在另一个 CPU 上。
Parallel Scavenge 收集器
Parallel Scavenge 收集器也是多线程收集器 ,其关注点是吞吐量(高效率的利用 CPU)。
是 JDK1.8 的默认收集器,可以使用
java -XX:+PrintCommandLineFlags -version命令查看
吞吐量(Throughput)就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值。
Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解,手工优化存在困难的时候,使用 此收集器配合自适应调节策略,把内存管理优化交给虚拟机去完成也是一个不错的选择。
新生代采用标记-复制算法,老年代采用标记-整理算法。

Parallel Old 收集器
Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器
![![[Pasted image 20231011234122.png]]](https://i-blog.csdnimg.cn/direct/8337d78ce5e24fac89fc27e5af68a90e.png)
CMS 收集器
CMS(Concurrent Mark Sweep)收集器 是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。
CMS(Concurrent Mark Sweep)收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
从名字中的 Mark Sweep 这两个词可以看出,CMS 收集器是由 标记-清除 算法实现的。它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:
-
初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快
-
并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。
因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。 -
重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
-
并发清除: 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。

这是一款优秀的垃圾收集器:并发收集、低停顿。但是它有下面三个明显的缺点:
CMS 收集器缺点
-
对 CPU 资源非常敏感,因此在 CPU 资源紧张的情况下,
CMS的性能会大打折扣。默认情况下,CMS启用的垃圾回收线程数是(CPU数量 + 3)/4,当 CPU 数量很大时,启用的垃圾回收线程数占比就越小。但如果 CPU 数量很小,例如只有 2 个 CPU,垃圾回收线程占用就达到了 50%,这极大地降低系统的吞吐量,无法接受。 -
CMS采用的是「标记-清除」算法,会产生大量的内存碎片,导致空间不连续,当出现大对象无法找到连续的内存空间时,就会触发一次Full GC,这会导致系统的停顿时间变长。 -
CMS无法处理浮动垃圾,当CMS在进行垃圾回收的时候,应用程序还在不断地产生垃圾,这些垃圾会在CMS垃圾回收结束之后产生,这些垃圾就是浮动垃圾,CMS无法处理这些浮动垃圾,只能在下一次 GC 时清理掉。
G1 收集器
G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器,以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。引入了基于区域(Region)的垃圾回收策略。它是从 JDK 1.7 版本开始引入的。
G1垃圾收集器的主要目标是实现更短的停顿时间和更高的吞吐量。
G1 收集器特点
被视为 JDK1.7 中 HotSpot 虚拟机的一个重要进化特征,在 JDK 9 时取代 CMS 成为了默认的垃圾收集器。它具备以下特点:
-
增量:
G1可以以增量方式执行垃圾回收,这意味着它不需要一次性回收整个堆空间,而是可以逐步、增量地清理。有助于控制停顿时间,尤其是在处理大型堆时。 -
并行与并发:
G1能充分利用 CPU、多核环境下的硬件优势,使用多个 CPU(CPU 或者 CPU 核心)来缩短Stop-The-World停顿时间。部分其他收集器原本需要停顿 Java 线程执行的GC动作,G1收集器仍然可以通过并发的方式让 java 程序继续执行。 -
分代收集:虽然
G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。 -
空间整合:与
CMS的“标记-清除”算法不同,G1 从整体来看是基于“标记-整理”算法实现的收集器;从局部上来看是基于“标记-复制”算法实现的。 -
可预测的停顿:这是
G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在垃圾收集上的时间不得超过 N 毫秒。
G1 收集器的分代理念
G1 是基于分代的思想进行设计的。它将堆内存分为多个大小相等的区域(Region),每个区域都可以是 Eden 区、Survivor 区或者 Old 区。

可以通过 -XX:G1HeapRegionSize=n 来设置 Region 的大小,可以设定为 1M、2M、4M、8M、16M、32M(不能超过)。
G1 有专门分配大对象的 Region 叫 Humongous 区,而不是让大对象直接进入老年代的 Region 中。在 G1 中,大对象的判定规则就是一个大对象超过了一个 Region 大小的 50%,比如每个 Region 是 2M,只要一个对象超过了 1M,就会被放入 Humongous 中,而且一个大对象如果太大,可能会横跨多个 Region 来存放。
G1 收集器运作过程
它的设计思想是将堆内存划分为多个大小相等的区域(Region),每个区域都可以是Eden、Survivor 或 Old 区域。G1垃圾收集器通过并发、增量和并行的方式,以区域为粒度进行垃圾回收,其工作过程如下:
-
初始标记(Initial Mark):G1垃圾收集器会首先标记出GC Roots能直接关联到的对象,并记录下这些对象的存活状态。在此阶段,应用程序的执行会停顿下来。
-
并发标记(Concurrent Marking):G1垃圾收集器并发进行标记工作,在应用程序运行的同时,标记剩余的存活对象。在这个阶段,G1会进行跨区域的引用扫描,标记存活对象。
-
最终标记(Final Mark):在并发标记阶段结束后,G1会做一次最终标记来修正并发标记期间有可能发生的引用变化。该阶段的停顿时间会较短。
-
筛选回收(Live Data Counting):G1根据各个区域内的垃圾量和存活对象数量等信息,选择最有价值的区域进行垃圾收集。这个阶段被称为G1的"Garbage-First"策略。
G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region (Garbage-First)
这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)
- 并发清理(Concurrent Cleanup):G1进行并发的垃圾清理工作,在应用程序运行的同时,回收垃圾区域中的无用对象。
![![[Pasted image 20231011235136.png]]](https://i-blog.csdnimg.cn/direct/4f5bc499d4f14f51ae74748a44e1ccd0.png)
G1垃圾收集器在整个垃圾回收过程中,会控制垃圾回收的停顿时间,尽量减少对应用程序的影响。它可以根据应用程序的需要动态调整各个阶段的时间比例,以达到更好的性能和吞吐量
相关文章:
Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾收集器
文章目录 垃圾回收机制Stop-the-World垃圾收集器垃圾收集器分类Serial 收集器Serial Old 收集器ParNew 收集器Parallel Scavenge 收集器Parallel Old 收集器CMS 收集器CMS 收集器缺点 G1 收集器G1 收集器特点G1 收集器的分代理念G1 收集器运作过程 垃圾回收机制 垃圾回收&…...
nano 命令:文本编辑器
一、命令简介 nano 是一个简单易用的文本编辑器,适合初学者和那些不需要复杂功能的用户。 相关命令(不同难度的编辑器): 初级难度:nano中级难度:vim终极难度:Emacs 二、命…...
【2020工业图像异常检测文献】SPADE
Sub-Image Anomaly Detection with Deep Pyramid Correspondences 1、Background 利用深度预训练特征的最近邻( kNN )方法在应用于整个图像时表现出非常强的异常检测性能。kNN 方法的一个局限性是缺乏描述图像中异常位置的分割图。 为了解决这一问题&a…...
C++QT医院专家门诊预约管理系统
目录 一、项目介绍 二、项目展示 三、源码获取 一、项目介绍 医院专家门诊预约管理系统 [要求] 该系统需创建和管理以下信息:1、门诊专家信息:专家姓名、编号、性别、年龄、职称、门诊科目、服务时间、门诊预约数据集等;2、门诊预约信息…...
在SpringBoot项目中利用Redission实现布隆过滤器(布隆过滤器的应用场景、布隆过滤器误判的情况、与位图相关的操作)
文章目录 1. 布隆过滤器的应用场景2. 在SpringBoot项目利用Redission实现布隆过滤器3. 布隆过滤器误判的情况4. 与位图相关的操作5. 可能遇到的问题(Redission是如何记录布隆过滤器的配置参数的)5.1 问题产生的原因5.2 解决方案5.2.1 方案一:…...
【prefect】python任务调度工具 Prefect | 可视化任务工具 | Python自动化的终极武器 | 高效数据管道管理
一、产品介绍 1、官方 Github https://github.com/PrefectHQ/prefect 2、官方文档 https://docs.prefect.io/3.0/get-started/index 3、Pgsql说明 正确的python链接pgsql如下: import psycopg2 from sqlalchemy import create_enginedef connect_with_psycopg2(…...
蓝禾,汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
蓝禾,汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推 ①蓝禾 【岗位】国内/国际电商运营,设计,…...
【面向对象】设计模式分类
java中设计模式共23种,根据使用场景可分为创建型模式、结构型模式、行为型模式。 创建型: 如何创建对象。 单例模式:保证一个类在一个程序中只能创建一个对象。例如windows任务管理器窗口只需要创建一个。单例模式只创建一个对象࿰…...
花朵识别系统Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
一、介绍 花朵识别系统。本系统采用Python作为主要编程语言,基于TensorFlow搭建ResNet50卷积神经网络算法模型,并基于前期收集到的5种常见的花朵数据集(向日葵、玫瑰、蒲公英、郁金香、菊花)进行处理后进行模型训练,最…...
中泰免签,准备去泰国旅游了吗?《泰语翻译通》app支持文本翻译和语音识别翻译,解放双手对着说话就能翻译。
泰国是很多中国游客的热门选择,现在去泰国旅游更方便了,因为泰国对中国免签了。如果你打算去泰国,那么下载一个好用的泰语翻译软件是很有必要的。 简单好用的翻译工具 《泰语翻译通》App就是为泰国旅游设计的,它翻译准确&#x…...
C++/Qt 集成 AutoHotkey
C/Qt 集成 AutoHotkey 前言AutoHotkey 介绍 方案一:子进程启动编写AutoHotkey脚本准备 AutoHotkey 运行环境编写 C/Qt 代码 方案二:显式动态链接方案探索编译动态链接库集成到C工程关于AutoHotkeyDll.dll中的函数原型 总结 前言 上一篇介绍了AutoHotkey…...
OpenMV学习第一步安装IDE_2024.09.20
用360浏览器访问星瞳科技官网,一直提示访问不了。后面换了IE浏览器就可以访问。第一个坑。...
RK3568平台(基础篇)万用表的使用
一.万用表的通断判断 万用表两个笔头的插法:黑笔头是插在COM的孔里面,红色笔头可以插在其他的三个孔里面,20A和mA分别用来测电流,另外一个孔可以用来测其他(电压 电阻)。 以下这个三角符号(像wifi一样的)可以用来测通断: 使用万用表的红笔和黑笔进行短接,这时候两端…...
more、less 命令:阅读文本
一、命令简介 more 和 less 都是用于查看文本文件内容的命令,但它们在显示方式和功能上有一些区别。 简单的说 less 是 more 的升级版:增加了搜索、跳转等功能。所以优先使用 less,可以不用 more 了。 二、命令参数 基…...
【笔记】1.3 塑性变形
一、塑性变形的方式 DDWs(Dislocation-Dipole Walls,位错偶极墙):指由两个位错构成的结构,它们以一种特定的方式排列在一起,形成一个稳定的结构单元。 DTs(Dislocation Tangles,位错…...
Java集合(三)
目录 Java集合(三) Java双列集合体系介绍 HashMap类 HashMap类介绍 HashMap类常用方法 HashMap类元素遍历 LinkedHashMap类 LinkedHashMap类介绍 LinkedHashMap类常用方法 LinkedHashMap类元素遍历 Map接口自定义类型去重的方式 Set接口和Ma…...
python:给1个整数,你怎么判断是否等于2的幂次方?
最近在csdn上刷到一个比较简单的题目,题目要求不使用循环和递归来实现检查1个整数是否等于2的幂次方,题目如下: 题目的答案如下: def isPowerofTwo(n):z bin(n)[2:]print(bin(n))if z[0] ! 1:return Falsefor i in z[1:]:if i !…...
Centos7安装gitlab-ce(rpm安装方式)
本章教程,主要介绍如何在Centos7安装gitlab-ce。 一、安装基础环境 安装gitlab-ce之前,我们需要安装一下jdk版本。 sudo yum install java-11-openjdk-devel二、下载安装包 这里我们下载的是rpm包。更多gitlab-ce版本可以在这里查看:https://…...
Flutter 获取手机连接的Wifi信息
测试版本 Flutter:3.7.6Dart:2.19.3 network_info_plus: 4.0.1 前言 我在做设备配网的时候,需要选择配网的WiFi。用下拉选择框展示WiFi列表。现在有个需求:默认展示的设备为手机连接的wifi。要实现这个需求只要能够获取到手机连接的wifi信息…...
誉龙视音频 Third/TimeSyn 远程命令执行复现
0x01 漏洞描述: 誉龙公司定位为系统级的移动视音频记录解决方案提供商,凭借其深厚的行业经验,坚持自主研发,匠心打造记录仪领域行业生态,提供开放式的记录仪APK、GB28181 SDK、国网B协议、管理平台软件OEM。誉龙视音频…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
