JVM专题十:JVM中的垃圾回收机制

在JVM专题九:JVM分代知识点梳理中,我们主要介绍了JVM为什么采用分代算法,以及相关的概念,本篇我们将详细拆分各个算法。

垃圾回收的概念

垃圾回收(Garbage Collection,GC)确实是计算机编程中的一项重要技术,它自动化了内存管理过程,解决了手动内存管理(如在C或C++中)的复杂性和潜在错误。

在没有垃圾回收的情况下,程序员需要负责申请和释放内存,这不仅容易出错,还可能导致内存泄漏和其他资源管理问题。垃圾回收的引入,使得程序员可以更专注于程序逻辑,而不是内存细节。

正如你提到的,垃圾回收的概念最早可以追溯到1960年的Lisp语言,它是为了解决手动内存管理的繁琐和低效问题。Java语言设计时,将垃圾回收作为其核心特性之一,以简化内存管理并提高开发效率。

Java中的垃圾回收机制主要依赖于以下几个方面:

  • 自动内存管理:JVM自动追踪对象的引用情况,确定哪些对象不再被使用。
  • 垃圾收集算法:JVM使用不同的算法(如标记-清除、复制、标记-清除-整理等)来识别和回收垃圾对象。
  • 垃圾收集器:JVM提供了多种垃圾收集器,以适应不同的应用场景和性能需求。

Java的finalize方法类似于C++中的析构函数,提供了在对象被回收前执行清理操作的机会。但由于finalize的执行时机不确定,且可能影响垃圾回收的性能,因此通常不推荐依赖它来进行关键的资源回收。

总的来说,垃圾回收是现代编程语言的一个重要特性,它帮助开发者编写更安全、更高效的程序。Java作为一门高级语言,通过其垃圾回收机制,显著简化了内存管理的复杂性。

Java中的垃圾回收机制

自动内存管理

JVM自动追踪对象的引用情况,确定哪些对象不再被使用。这也是讨论垃圾回收的前提(只有知道谁是垃圾,才可以进行垃圾回收吗),常用的是引用计数法、可达性分析,垃圾判断

引用计数法

引用计数法是一种简单直接的垃圾回收算法。在这种方法中,每个对象维护一个计数器,用于记录有多少个引用指向该对象:

  1. 引用增加:当有引用指向一个对象时,对象的引用计数加一。
  2. 引用消失:当引用被清除时,对应的对象引用计数减一。
  3. 垃圾回收:当对象的引用计数为零时,表示没有任何引用指向该对象,该对象可以被垃圾回收。

优点

  • 垃圾对象可以很快被发现并回收。

缺点

  • 难以处理循环引用问题,即两个或多个对象相互引用,但对其他对象没有引用,按照引用计数法,这些对象的引用计数不为零,不会被回收。
  • 维护引用计数需要额外的开销,尤其是在大量对象和频繁更新引用的场景下。

可达性分析

可达性分析是JVM中更常用的垃圾回收算法,它基于一系列被称为GC Roots的根对象进行:

  1. GC Roots:包括Java方法栈中的局部变量静态变量本地方法栈中的引用等。
  2. 标记过程:从GC Roots开始,所有可达的对象都会被标记为存活,可达的是存活哈。
  3. 清除过程:未被标记的对象被认为是垃圾,可以被回收。

优点

  • 可以处理循环引用问题,因为可达性分析不依赖于引用计数,只要没有GC Roots可达的路径,对象就会被回收。
  • 适用于大规模的应用程序,因为它可以更精确地识别存活对象。

缺点

  • 需要暂停应用程序(Stop-the-World)来执行标记和清除过程,尤其是在Full GC时。
  • 标记和清除过程可能需要较长时间,尤其是在堆内存很大时。

STW

"Stop The World"(STW)是Java虚拟机(JVM)垃圾回收中的一个术语,指的是在执行垃圾回收时,JVM必须暂停应用程序的执行,以便在一致的状态进行内存的回收和整理。以下是STW的一些关键点:

  1. 全局一致性:STW确保了在垃圾回收期间,整个堆的状态是一致的,避免了并发执行时对内存状态的不一致性。

  2. 减少复杂性:通过暂停应用程序的执行,垃圾回收器可以简化其算法,因为不需要处理并发修改的问题。

  3. 性能影响:STW会导致应用程序的延迟增加,因为所有的应用线程都被挂起,直到垃圾回收完成。

  4. 优化目标:现代垃圾回收器的设计目标之一是减少STW的时间,以提高应用程序的响应性和吞吐量。

  5. 类型

    • Minor GC:通常很快,对新生代进行回收,STW时间较短。
    • Major GC 或 Full GC:涉及整个堆的回收,STW时间较长,对性能的影响也更大。
  6. 并发收集:一些垃圾回收器如CMS(Concurrent Mark-Sweep)和G1(Garbage-First),通过并发标记和清除阶段减少STW时间。

  7. 低延迟收集器:例如ZGC和Shenandoah,它们通过并发处理大部分GC阶段,极大地减少了STW事件。

  8. 调优:通过调整JVM参数和选择合适的垃圾回收器,可以优化STW事件,减少其对应用程序性能的影响。

  9. 监控:通过监控工具,如JConsole或VisualVM,可以观察STW事件和持续时间,以评估垃圾回收对性能的影响。

  10. 应用设计:应用程序设计时,应考虑到STW的影响,例如,避免在性能敏感的路径上进行长时间的GC。

STW是垃圾回收的一个挑战,现代JVM通过各种策略和算法来减少STW的影响,以提供更平滑的应用程序性能。

垃圾收集算法

标记-清除(Mark-Sweep)算法

标记-清除算法(Mark-Sweep)是一种基础的垃圾回收算法,如上图所示,它通过以下两个主要步骤来回收内存中的垃圾对象:

  1. 标记阶段:算法从根集合(GC Roots)开始,使用可达性分析法遍历所有可达对象,并将这些存活对象进行标记。

  2. 清除阶段:算法再次遍历内存区域,这次是为了识别那些未被标记的对象,即那些不再被引用的垃圾对象,并将它们清理掉,从而释放内存空间。

这种算法的优点在于逻辑简单,易于实现,但它也有明显的缺点,如上图回收后JVM内存图,会产生内存碎片问题:由于对象是逐个被清理的,这可能导致内存中出现许多小的空闲区域,也就是JVM内存碎片。内存碎片过多时,当程序需要分配较大的连续内存块时,可能无法找到足够的空间,即便总的空闲内存是足够的。这种情况可能导致提前触发新一轮的垃圾收集,影响程序性能。

复制(Copying)算法

复制算法(Copying)是在标记清除算法上演化而来的,用于解决标记清除算法的内存碎片问题。如上图所示:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当其中一块使用完,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样就保证了内存的连续性,逻辑清晰,运行高效。

优势:

  1. 简单高效:复制算法避免了标记-清除算法中内存碎片的问题,实现简单,运行高效3。
  2. 高吞吐量:由于只处理存活对象,所以效率较高,尤其适合新生代对象存活率低的情况1。
  3. 内存分配快速:复制算法完成后,空闲内存是连续的,分配内存时只需移动堆顶指针,非常快速。

缺点:

  1. 内存利用率降低:由于需要两个内存区域,实际使用的内存只有一半。
  2. 对象复制成本:需要复制存活对象,这会带来一定的性能开销。上述缺点让人

标记-清除-整理(Mark-Sweep-Compact)算法

标记-清除-整理(Mark-Sweep-Compact)算法是一种垃圾回收算法,这个算法分为三个阶段:

  1. 标记(Mark):在这个阶段,垃圾回收器遍历所有可达对象,从根对象开始,标记所有可达的对象。这意味着垃圾回收器会识别出所有仍然在使用中的对象,以便在后续阶段不会被错误地回收。

  2. 清除(Sweep):一旦标记阶段完成,垃圾回收器将遍历堆内存,清除所有未被标记的对象。这个阶段可能会留下内存碎片,因为对象是逐个被清除的,而不是成块地清除。

  3. 整理(Compact):为了解决内存碎片问题,这个阶段会将所有存活的对象向堆的一端移动,使得它们紧密排列。然后,回收器可以简单地清理掉边界之外的所有内存。整理阶段完成后,堆内存中存活的对象是连续存放的,这有助于提高内存访问的局部性,从而提高性能。

优点:

  • 没有内存碎片:通过整理阶段,可以避免内存碎片的问题,使得内存使用更加高效。
  • 适用于老年代:由于老年代的对象存活率高,标记-清除-整理算法可以有效地管理这些对象。

缺点:

  • 效率问题:整理阶段可能需要移动大量的对象,这可能会导致相对较高的开销。
  • 暂停时间:标记和清除阶段可能会引起应用程序的暂停,尤其是在处理大量对象时。

在实际的JVM实现中,标记-清除-整理算法可能会有所变化,以适应不同的垃圾回收需求和优化性能。例如,某些实现可能会采用增量或并发的垃圾回收策略来减少应用程序的暂停时间。此外,现代JVM通常会结合使用多种垃圾回收算法,以适应不同内存区域的特点。

分代收集算法

分代收集算法(Generational Collection)是一个结合了多种基础垃圾回收算法的策略,它根据对象的生命周期特点,将堆内存划分为不同的区域,并对这些区域采用最适合的垃圾回收算法。

根据对象存活周期的不同会将内存划分为几块,一般是把 Java 堆分为新生代和老年代,新生代又可以分为Eden区和Survivor区,其中Survivor区又会分To与From区;这样就可以根据各个年代的特点采用最适当的收集算法,如上图所示。

在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用标记清理或者标记整理算法来进行回收。

Eden区
  • Eden区是新生代的一部分,大多数新创建的对象首先被分配到这里。
  • 据 IBM 公司之前的研究表明,有将近 98% 的对象是朝生夕死,正是由于对象的朝生夕死特性,Eden区经常需要进行Minor GC来回收垃圾对象。通过 Minor GC 之后,Eden 区中绝大部分对象会被回收,而那些无需回收的存活对象,将会进到 Survivor 的 From 区,如果 From 区不够,则直接进入 To 区。
Survivor区
  • Survivor区有两个,From和To,它们的作用是作为Eden区和Old区之间的缓冲。
  • 通过Minor GC,存活的对象从Eden区和From区复制到To区,这样可以减少直接晋升到老年代的对象数量,降低Major GC的频率。
  • 两个Survivor区的设计有助于避免内存碎片,并确保每次GC后都有一个Survivor区是空的,另一个是没有碎片的。

Survivor区的划分原因

  • 如果只有一个Survivor区,每次Minor GC后,存活对象和需要清除的对象都会混在一起,导致内存碎片问题。
  • 两个Survivor区可以在每次Minor GC后,将存活对象复制到空的Survivor区,从而保持内存的连续性。
Old区
  • 老年代占据了Java堆的大部分空间,主要用于存放长期存活的对象。
  • 由于老年代中对象的存活率高,通常使用标记-清除或标记-整理算法进行垃圾回收。

常用的垃圾回收器

上面介绍的两个小节自动内存管理和垃圾收集算法都是从理论上介绍了设计思路,具体的实现再落在具体的垃圾回收器上,下面罗列了目前主流的垃圾回收器。

Java虚拟机(JVM)提供了多种垃圾回收器,以适应不同的应用场景和性能要求。以下是一些常用的垃圾回收器及其特点:

  1. Serial GC:单线程,适合小内存和单核环境。
  2. ParNew GC:Serial的多线程版本,适合多核环境。
  3. Parallel Scavenge GC:追求吞吐量,适合后台处理。
  4. Serial Old GC:老年代单线程,使用标记-整理算法。
  5. Parallel Old GC:老年代多线程,与Parallel Scavenge配合。
  6. CMS GC:老年代并发收集,减少停顿时间,但可能产生内存碎片。
  7. G1 GC:堆分割为区域,追求低延迟和高吞吐量。
  8. ZGC:低延迟,几乎不牺牲吞吐量,适合大堆内存。
  9. Shenandoah:同样以低延迟为目标,由Red Hat开发。

每种垃圾回收器都有其特定的使用场景和优化目标。开发者可以根据应用程序的具体需求,选择合适的垃圾回收器来优化性能。随着Java技术的发展,新的垃圾回收器也在不断地被引入和优化。

小节

本章我们主要介绍了Java的垃圾机制,包括垃圾回收基本概念,重点介绍了垃圾回收机制中自动内存管理与垃圾收集算法。简短罗列了下常用见的垃圾回收器。下一篇我们见重点介绍各个垃圾回收器的特定、及适用的常见。 

最后还是提一个小问题:你们线上JVM的参数是什么,使用的是什么垃圾回收器呢?

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

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

相关文章

【自然语言处理系列】探索NLP:使用Spacy进行分词、分句、词性标注和命名实体识别,并以《傲慢与偏见》与全球恐怖活动两个实例文本进行分析

本文深入探讨了scaPy库在文本分析和数据可视化方面的应用。首先,我们通过简单的文本处理任务,如分词和分句,来展示scaPy的基本功能。接着,我们利用scaPy的命名实体识别和词性标注功能,分析了Jane Austen的经典小说《傲…

discuz插件之优雅草超级列表互动增强v1.2版本更新

https://doc.youyacao.com/9/2142 v1.2更新 discuz插件之优雅草超级列表互动增强v1.2版本更新 [title]20220617 v1.2发布[/title] 增加了对php8的支持 增加了 对discuz3.5的支持

RocketMQ源码学习笔记:Broker启动流程

这是本人学习的总结,主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、Broker启动流程2、一些重要的类2.1、MappedFile2.2、MessgeStore2.3、MessageStore的加载启动流程 3、技术亮点3.1、 内存映射3.1.1、简介3.1.2、源码 1、Broker启动流程 Broker启动流程…

RabbitMQ中lazyqueue队列

lazyqueue队列非常强悍 springboot注解方式开启 // 使用注解的方式lazy.queue队列模式 非常GoodRabbitListener(queuesToDeclare Queue(name "lazy.queue",durable "true",arguments Argument(name "x-queue-mode",value "lazy&…

3.蓝牙模块HC-08

目录 一.简介​编辑 二.主要参数 三.模块引脚说明 四、LED指示灯状态 五.AT指令 5.1AT指令重点 5.2 AT指令注意点 5.3 AT指令集 六.AT常用指令 6.1 测试指令 AT 6.2 查询当前参数ATRX 6.3设置主从模式 ATROLE 6.4设置蓝牙模式 ATNAME 6.5 设置波特率 …

YOLOv5改进(八)--引入Soft-NMS非极大值抑制

文章目录 1、前言2、各类NMS代码实现2.1、general.py 3、各类NMS实现3.1、Soft-NMS3.2、GIoU-NMS3.3、DIoU-NMS3.4、CIoU-NMS3.5、EIoU-NMS 4、目标检测系列文章 1、前言 目前yolov5使用的是NMS进行极大值抑制,本篇文章是要将各类NMS添加到yolov5中,同时…

6.25作业

1.整理思维导图 2.终端输入两个数,判断两数是否相等,如果不相等,判断大小关系 #!/bin/bash read num1 read num2 if [ $num1 -eq $num2 ] then echo num1num2 elif [ $num1 -gt $num2 ] then echo "num1>num2" else echo &quo…

200.回溯算法:子集||(力扣)

class Solution { public:vector<int> res; // 当前子集vector<vector<int>> result; // 存储所有子集void backtracing(vector<int>& nums, int index, vector<bool>& used) {result.push_back(res); // 将当前…

【嵌入式Linux】<总览> 进程间通信(更新中)

文章目录 前言 一、管道 1. 概念 2. 匿名管道 3. 有名管道 二、内存映射区 1. 概念 2. mmap函数 3. 进程间通信&#xff08;有血缘关系&#xff09; 4. 进程间通信&#xff08;没有血缘关系&#xff09; 5. 拷贝文件 前言 在文章【嵌入式Linux】&#xff1c;总览&a…

浏览器断点调试(用图说话)

浏览器断点调试&#xff08;用图说话&#xff09; 1、开发者工具2、添加断点3、查看变量值 浏览器断点调试 有时候我们需要在浏览器中查看 html页面的js中的变量值。1、开发者工具 打开浏览器的开发者工具 按F12 &#xff0c;没反应的话按FnF12 2、添加断点 3、查看变量值

清理占道经营商贩自砸西瓜?智慧城管AI视频方案助力城市街道管理

一、背景分析 近日有新闻报道&#xff0c;在山西太原&#xff0c;城管凌晨3时许查处商贩占道经营&#xff0c;商贩将西瓜砸碎一地&#xff0c;引起热议。据悉&#xff0c;事件发生的五龙口街系当地主要街道&#xff0c;来往车辆众多。该商贩长期在该地段占道经营&#xff0c;影…

昇思25天学习打卡营第2天|快速入门

快速入门 操作步骤1.引入依赖包2.下载Mnist数据集3.划分训练集和测试集4.数据预处理5.网络构建6.模型训练7.保存模型8.加载模型9.模型预测 今天通过昇思大模型平台AI实验室提供的在线Jupyter工具&#xff0c;快速入门MindSpore。 目标&#xff1a;通过MindSpore的API快速实现一…

云计算 | 期末梳理(下)

1.模运算 2. 拓展欧几里得算法 3.扩散和混淆、攻击的分类 香农的贡献:定义了理论安全性,提出扩散和混淆原则,奠定了密码学的理论基础。扩散:将每一位明文尽可能地散布到多个输出密文中去,以更隐蔽明文数字的统计特性。混淆:使密文的统计特性与明文密钥之间的关系尽量复杂…

深入解析直播带货系统源码:短视频商城APP开发全攻略

本篇文章&#xff0c;小编将深入解析直播带货系统的源码&#xff0c;并为开发短视频商城APP提供全攻略&#xff0c;助力开发者打造高效、稳定的带货平台。 一、直播带货系统概述 直播带货系统主要由直播模块、商品管理模块、订单处理模块、用户管理模块、以及支付模块等组成。…

Ubuntu20.04使用Samba

目录 一、Samba介绍 Samba 的主要功能 二、启动samba 三、主机操作 四、Ubuntu与windows系统中文件互联 五、修改samba路径 一、Samba介绍 Samba 是一个开源软件套件&#xff0c;用于在 Linux 和 Unix 系统上实现 SMB&#xff08;Server Message Block&#xff09;协议…

速卖通自养号测评:安全高效的推广手段

在速卖通平台上&#xff0c;卖家们常常寻求各种方法来提升商品的曝光、转化率和店铺权重。其中&#xff0c;自养号测评作为一种低成本、高回报的推广方式&#xff0c;备受关注。然而&#xff0c;若操作不当&#xff0c;也可能带来风险。以下是如何安全有效地进行自养号测评的指…

VS Code 使用 Makefile 运行 CPP项目

Installing the MinGW-w64 toolchainCMake Toolsmakelist.txt报错 1报错 2报错 3生成了 Makefile &#xff0c;如何使用 make 命令 Installing the MinGW-w64 toolchain 参见文档 将 GCC 与 MinGW 结合使用 CMake Tools 参见文档 Linux 上的 CMake 工具入门 CMake 的使用 …

关于Pycharm右下角不显示解释器interpreter的问题解决

关于Pycharm右下角不显示解释器interpreter的问题 在安装新的Pycharm后&#xff0c;发现右下角的 interpreter 的选型消失了&#xff1a; 觉得还挺不习惯的&#xff0c;于是网上找解决办法&#xff0c;无果。 自己摸索了一番后&#xff0c;发现解决办法如下&#xff1a; 勾…

37岁,被裁员,失业三个月,被面试官嫌弃“太水”:就这也叫10年以上工作经验?

今年部门要招两个自动化测试&#xff0c;这几个月我面试了几十位候选人。发现一个很奇怪的现象&#xff0c;面试中一问到元素定位、框架api、脚本编写之类的&#xff0c;很多候选人都对答如流。但是一问到实际项目&#xff0c;比如“项目中UI自动化和接口自动化如何搭配使用&am…

电商平台家电以旧换新销售额增长超80%

记者近日从国家发展和改革委员会举办的新闻发布会上获悉&#xff0c;今年1—5月份&#xff0c;主要电商平台家电以旧换新销售额增长超过80%&#xff0c;以旧换新成为推动家电消费增长的重要因素。 今年3月&#xff0c;国务院印发了《推动大规模设备更新和消费品以旧换新行动方…