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 中的一些垃圾收集器,如 G1ZGC(下文有详细讲解),都会尽可能地减少了"Stop The World"的时间,通过并发的垃圾收集,提高应用的响应性能。

垃圾收集器

如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。Java 垃圾收集器(Garbage Collector, GC)是 Java 虚拟机(JVM)的一部分,它自动管理内存,回收不再使用的对象所占用的内存空间。这有助于防止内存泄漏,并且使得开发人员可以更专注于业务逻辑的编写而不是内存管理。

没有万能的垃圾收集器,只有根据具体应用场景选择适合自己的垃圾收集器。垃圾收集器是垃圾回收算法(如引用计数法、标记清除法、标记整理法、复制算法等)的具体实现。它的主要任务是识别并回收那些不再被程序使用的对象所占用的内存空间,从而避免内存泄漏和内存溢出的问题。

垃圾收集器分类

就目前来说,JVM 的垃圾收集器主要分为两大类:分代收集器分区收集器,分代收集器的代表是 CMS,分区收集器的代表是 G1ZGC

JDK 默认垃圾收集器(使用 java -XX:+PrintCommandLineFlags -version 命令查看):

  • JDK 8:Parallel Scavenge(新生代)+ Parallel Old(老年代)
  • JDK 9 ~ JDK20: G1

在这里插入图片描述

Serial 收集器

Serial(串行)收集器是最基本、历史最悠久的垃圾收集器。此收集器是一个单线程收集器了。

它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “STW Stop The World” ),直到它收集结束。

新生代采用标记-复制算法,老年代采用标记-整理算法。

Serial 收集器

Serial 收集器简单而高效(与其他收集器的单线程相比)。由于没有线程交互的开销,自然可以获得很高的单线程收集效率,对于运行在 Client 模式下的虚拟机来说是个不错的选择

Serial Old 收集器

Serial 收集器的老年代版本,它同样是一个单线程收集器。它主要有两大用途:一种用途是在 JDK1.5 以及以前的版本中与 Parallel Scavenge 收集器搭配使用,另一种用途是作为 CMS 收集器的后备方案。

![[Pasted image 20231011233428.png]]

ParNew 收集器

ParNew 收集器是 Serial 收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和 Serial 收集器完全一样。

新生代采用标记-复制算法,老年代采用标记-整理算法。

![[Pasted image 20231011233540.png]]

并行和并发概念补充

  • 并行(Parallel):指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。

  • 并发(Concurrent):指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器运行在另一个 CPU 上。

Parallel Scavenge 收集器

Parallel Scavenge 收集器也是多线程收集器 ,其关注点是吞吐量(高效率的利用 CPU)。

是 JDK1.8 的默认收集器,可以使用
java -XX:+PrintCommandLineFlags -version 命令查看

吞吐量(Throughput)就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值

Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解,手工优化存在困难的时候,使用 此收集器配合自适应调节策略,把内存管理优化交给虚拟机去完成也是一个不错的选择。

新生代采用标记-复制算法,老年代采用标记-整理算法。

Parallel Old收集器运行示意图

Parallel Old 收集器

Parallel Scavenge 收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及 CPU 资源的场合,都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器

![[Pasted image 20231011234122.png]]

CMS 收集器

CMS(Concurrent Mark Sweep)收集器 是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用。

CMS(Concurrent Mark Sweep)收集器是 HotSpot 虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作

从名字中的 Mark Sweep 这两个词可以看出,CMS 收集器是由 标记-清除 算法实现的。它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:

  1. 初始标记: 暂停所有的其他线程,并记录下直接与 root 相连的对象,速度很快

  2. 并发标记: 同时开启 GC 和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。
    因为用户线程可能会不断的更新引用域,所以 GC 线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方

  3. 重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短

  4. 并发清除: 开启用户线程,同时 GC 线程开始对未标记的区域做清扫。

CMS 收集器

这是一款优秀的垃圾收集器:并发收集、低停顿。但是它有下面三个明显的缺点:

CMS 收集器缺点
  1. 对 CPU 资源非常敏感,因此在 CPU 资源紧张的情况下,CMS 的性能会大打折扣。默认情况下,CMS 启用的垃圾回收线程数是(CPU数量 + 3)/4,当 CPU 数量很大时,启用的垃圾回收线程数占比就越小。但如果 CPU 数量很小,例如只有 2 个 CPU,垃圾回收线程占用就达到了 50%,这极大地降低系统的吞吐量,无法接受。

  2. CMS 采用的是「标记-清除」算法,会产生大量的内存碎片,导致空间不连续,当出现大对象无法找到连续的内存空间时,就会触发一次 Full GC,这会导致系统的停顿时间变长。

  3. 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 的另一个大优势,降低停顿时间是 G1CMS 共同的关注点,但 G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为 M 毫秒的时间片段内,消耗在垃圾收集上的时间不得超过 N 毫秒。

G1 收集器的分代理念

G1 是基于分代的思想进行设计的。它将堆内存分为多个大小相等的区域(Region),每个区域都可以是 Eden 区、Survivor 区或者 Old 区。

在这里插入图片描述

可以通过 -XX:G1HeapRegionSize=n 来设置 Region 的大小,可以设定为 1M、2M、4M、8M、16M、32M(不能超过)。

G1 有专门分配大对象的 RegionHumongous 区,而不是让大对象直接进入老年代的 Region 中。在 G1 中,大对象的判定规则就是一个大对象超过了一个 Region 大小的 50%,比如每个 Region 是 2M,只要一个对象超过了 1M,就会被放入 Humongous 中,而且一个大对象如果太大,可能会横跨多个 Region 来存放。

G1 收集器运作过程

它的设计思想是将堆内存划分为多个大小相等的区域(Region),每个区域都可以是EdenSurvivorOld 区域。G1垃圾收集器通过并发、增量和并行的方式,以区域为粒度进行垃圾回收,其工作过程如下:

  1. 初始标记(Initial Mark):G1垃圾收集器会首先标记出GC Roots能直接关联到的对象,并记录下这些对象的存活状态。在此阶段,应用程序的执行会停顿下来。

  2. 并发标记(Concurrent Marking):G1垃圾收集器并发进行标记工作,在应用程序运行的同时,标记剩余的存活对象。在这个阶段,G1会进行跨区域的引用扫描,标记存活对象。

  3. 最终标记(Final Mark):在并发标记阶段结束后,G1会做一次最终标记来修正并发标记期间有可能发生的引用变化。该阶段的停顿时间会较短。

  4. 筛选回收(Live Data Counting):G1根据各个区域内的垃圾量和存活对象数量等信息,选择最有价值的区域进行垃圾收集。这个阶段被称为G1的"Garbage-First"策略。

G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region (Garbage-First)
这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)

  1. 并发清理(Concurrent Cleanup):G1进行并发的垃圾清理工作,在应用程序运行的同时,回收垃圾区域中的无用对象

![[Pasted image 20231011235136.png]]

G1垃圾收集器在整个垃圾回收过程中,会控制垃圾回收的停顿时间,尽量减少对应用程序的影响。它可以根据应用程序的需要动态调整各个阶段的时间比例,以达到更好的性能和吞吐量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/429597.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux笔记】如何将内容从一个文件复制到另一个文件

比如:将文件tmp_file.txt中的部分数据,复制到file01.txt中去 tmp_file.txt文中内容: file01.txt为空文档 一、使用vi编辑器 I、文件中直接使用:e 目标文件进行切换文件复制 1、打开被复制文件 vi tmp_file.txt 2、进入一般命令模式 默认情况为…

排序-----归并排序(递归版)

核心思想:假设数组前后两部分各自有序,然后各定义两个指针,谁小谁放到新开辟的数组里面,最后把新开辟的数组赋值给原数组就完成了。要使前后两部分有序就采用递归的方式,不断往下划分块,最后一层划分为两个…

SVM原理

SVM 这里由于过了很长时间 博主当时因为兴趣了解了下 博主现在把以前的知识放到博客上 作为以前的学习的一个结束 这些东西来自其他资料上 小伙伴看不懂英文的自行去翻译下吧 博主就偷个懒了 多维空间和低维空间 不一样的分法,将数据映射到高维 &…

鸿蒙OpenHarmony【轻量系统内核扩展组件(动态加载)】子系统开发

基本概念 在硬件资源有限的小设备中,需要通过算法的动态部署能力来解决无法同时部署多种算法的问题。以开发者易用为主要考虑因素,同时考虑到多平台的通用性,LiteOS-M选择业界标准的ELF加载方案,方便拓展算法生态。LiteOS-M提供类…

ZYNQ学习--AXI总线协议

一、AXI 总线简介 AXI(Advanced Extensible Interface)高级拓展总线是AMBA(Advanced Microcontroller Bus Architecture)高级微控制总线架构中的一个高性能总线协议,由ARM公司开发。AXI总线协议被广泛应用于高带宽、低…

PyQt5 导入ui文件报错 AttributeError: type object ‘Qt‘ has no attribute

问题描述: 利用 PyQt5 编写可视化界面是较为普遍的做法,但是使用全新UI版本的 Pycharm 修改之前正常的UI文件时,在没有动其他代码的情况下发现出现以下报错 AttributeError: type object Qt has no attribute Qt::ContextMenuPolicy::Defaul…

JavaEE: 深入探索TCP网络编程的奇妙世界(四)

文章目录 TCP核心机制TCP核心机制四: 滑动窗口为啥要使用滑动窗口?滑动窗口介绍滑动窗口出现丢包咋办? TCP核心机制五: 流量控制 TCP核心机制 上一篇文章 JavaEE: 深入探索TCP网络编程的奇妙世界(三) 书接上文~ TCP核心机制四: 滑动窗口 为啥要使用滑动窗口? 之前我们讨…

BERT的代码实现

目录 1.BERT的理论 2.代码实现 2.1构建输入数据格式 2.2定义BERT编码器的类 2.3BERT的两个任务 2.3.1任务一:Masked Language Modeling MLM掩蔽语言模型任务 2.3.2 任务二:next sentence prediction 3.整合代码 4.知识点个人理解 1.BERT的理论 B…

深度学习02-pytorch-08-自动微分模块

​​​​​​​ 其实自动微分模块,就是求相当于机器学习中的线性回归损失函数的导数。就是求梯度。 反向传播的目的: 更新参数, 所以会使用到自动微分模块。 神经网络传输的数据都是 float32 类型。 案例1: 代码功能概述: 该…

鸿蒙Harmony应用开发,数据驾驶舱 项目结构搭建

对于一个项目而言,在拿到我们的开发任务后,我们最重要的就是技术的选型。选型定下来了之后我们便开始脚手架的搭建,然后开始撸代码,开搞. 首先我们需要对一些常见依赖库的引入 我们需要再oh-package.json5的dependencies节点下面…

8--SpringBoot原理分析、注解-详解(面试高频提问点)

目录 SpringBootApplication 1.元注解 --->元注解 Target Retention Documented Inherited 2.SpringBootConfiguration Configuration Component Indexed 3.EnableAutoConfiguration(自动配置核心注解) 4.ComponentScan Conditional Co…

基于PHP的新闻管理系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于phpMySQL的新闻管理系统。…

JavaWeb--纯小白笔记03:servlet入门---动态网页的创建

笔记:index.html在tomcat中为默认的名字,html里面的语法不严谨。改配置文件要小心,不然容易删掉其他 Servlet:服务器端小程序,写动态网页需要用Servlet,普通的java类通过继承HttpServlet,可以响…

【GUI设计】基于Matlab的图像处理GUI系统(1),用matlab实现

博主简介:matlab图像代码项目合作(扣扣:3249726188) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于Matlab的图像处理GUI系统,用matlab实现。 本次内容主要分为两部分&a…

Why is OpenAI image generation Api returning 400 bad request in Unity?

题意:为什么 OpenAI 图像生成 API 在 Unity 中返回 400 Bad Request 错误? 问题背景: Im testing out dynamically generating images using OpenAI API in Unity. Amusingly, I actually generated most of this code from chatGPT. 我正在…

【笔记】第二节 轧制、热处理和焊接工艺

2.2 钢轨的轧制工艺 坯料进厂按标准验收, 然后装加热炉加热, 加热好的钢坯经高压水除鳞后进行轧制。轧出的钢轨经锯切、打印到中央冷床冷却, 然后装缓冷坑进行缓冷。缓冷后的钢轨进行矫直、轨端加工和端头淬火。钢轨入库前逐根进行探伤和外观检查。 钢轨的轧制 #mermaid-svg-…

foreach,for in和for of的区别

forEach 不能使用break return 结束并退出循环 for in 和 for of 可以使用break return; for in 遍历的是数组的索引(即键名),而for of遍历的是数组元素值。 for of 遍历的只是数组内的元素,而不包括数组的原型属性…

后端-navicat查找语句(单表与多表)

表格字段设置如图 语句&#xff1a; 1.输出 1.输出name和age列 SELECT name,age from student 1.2.全部输出 select * from student 2.where子语句 1.运算符&#xff1a; 等于 >大于 >大于等于 <小于 <小于等于 ! <>不等于 select * from stude…

JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操

JdbcTemplate是Spring框架中的一个重要组件&#xff0c;主要用于简化JDBC数据库操作。它提供了许多常用的方法&#xff0c;如查询、插入、更新、删除等。本文将介绍JdbcTemplate的常用方法及其使用方式&#xff0c;以及参数绑定和删除数据的方法。 一、JdbcTemplate常用方法 查…

钉钉与MySQL对接集成获取部门列表2.0打通EXECUTE语句

钉钉与MySQL对接集成获取部门列表2.0打通EXECUTE语句 接入系统&#xff1a;钉钉 钉钉是阿里巴巴集团打造的企业级智能移动办公平台&#xff0c;是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工…