JVM专题十:JVM中的垃圾回收机制
在JVM专题九:JVM分代知识点梳理中,我们主要介绍了JVM为什么采用分代算法,以及相关的概念,本篇我们将详细拆分各个算法。
垃圾回收的概念
垃圾回收(Garbage Collection,GC)确实是计算机编程中的一项重要技术,它自动化了内存管理过程,解决了手动内存管理(如在C或C++中)的复杂性和潜在错误。
在没有垃圾回收的情况下,程序员需要负责申请和释放内存,这不仅容易出错,还可能导致内存泄漏和其他资源管理问题。垃圾回收的引入,使得程序员可以更专注于程序逻辑,而不是内存细节。
正如你提到的,垃圾回收的概念最早可以追溯到1960年的Lisp语言,它是为了解决手动内存管理的繁琐和低效问题。Java语言设计时,将垃圾回收作为其核心特性之一,以简化内存管理并提高开发效率。
Java中的垃圾回收机制主要依赖于以下几个方面:
- 自动内存管理:JVM自动追踪对象的引用情况,确定哪些对象不再被使用。
- 垃圾收集算法:JVM使用不同的算法(如标记-清除、复制、标记-清除-整理等)来识别和回收垃圾对象。
- 垃圾收集器:JVM提供了多种垃圾收集器,以适应不同的应用场景和性能需求。
Java的finalize方法类似于C++中的析构函数,提供了在对象被回收前执行清理操作的机会。但由于finalize的执行时机不确定,且可能影响垃圾回收的性能,因此通常不推荐依赖它来进行关键的资源回收。
总的来说,垃圾回收是现代编程语言的一个重要特性,它帮助开发者编写更安全、更高效的程序。Java作为一门高级语言,通过其垃圾回收机制,显著简化了内存管理的复杂性。
Java中的垃圾回收机制
自动内存管理
JVM自动追踪对象的引用情况,确定哪些对象不再被使用。这也是讨论垃圾回收的前提(只有知道谁是垃圾,才可以进行垃圾回收吗),常用的是引用计数法、可达性分析,垃圾判断
引用计数法

引用计数法是一种简单直接的垃圾回收算法。在这种方法中,每个对象维护一个计数器,用于记录有多少个引用指向该对象:
- 引用增加:当有引用指向一个对象时,对象的引用计数加一。
- 引用消失:当引用被清除时,对应的对象引用计数减一。
- 垃圾回收:当对象的引用计数为零时,表示没有任何引用指向该对象,该对象可以被垃圾回收。
优点:
- 垃圾对象可以很快被发现并回收。
缺点:
- 难以处理循环引用问题,即两个或多个对象相互引用,但对其他对象没有引用,按照引用计数法,这些对象的引用计数不为零,不会被回收。
- 维护引用计数需要额外的开销,尤其是在大量对象和频繁更新引用的场景下。
可达性分析

可达性分析是JVM中更常用的垃圾回收算法,它基于一系列被称为GC Roots的根对象进行:
- GC Roots:包括Java方法栈中的局部变量、静态变量、本地方法栈中的引用等。
- 标记过程:从GC Roots开始,所有可达的对象都会被标记为存活,可达的是存活哈。
- 清除过程:未被标记的对象被认为是垃圾,可以被回收。
优点:
- 可以处理循环引用问题,因为可达性分析不依赖于引用计数,只要没有GC Roots可达的路径,对象就会被回收。
- 适用于大规模的应用程序,因为它可以更精确地识别存活对象。
缺点:
- 需要暂停应用程序(Stop-the-World)来执行标记和清除过程,尤其是在Full GC时。
- 标记和清除过程可能需要较长时间,尤其是在堆内存很大时。
STW

"Stop The World"(STW)是Java虚拟机(JVM)垃圾回收中的一个术语,指的是在执行垃圾回收时,JVM必须暂停应用程序的执行,以便在一致的状态进行内存的回收和整理。以下是STW的一些关键点:
-
全局一致性:STW确保了在垃圾回收期间,整个堆的状态是一致的,避免了并发执行时对内存状态的不一致性。
-
减少复杂性:通过暂停应用程序的执行,垃圾回收器可以简化其算法,因为不需要处理并发修改的问题。
-
性能影响:STW会导致应用程序的延迟增加,因为所有的应用线程都被挂起,直到垃圾回收完成。
-
优化目标:现代垃圾回收器的设计目标之一是减少STW的时间,以提高应用程序的响应性和吞吐量。
-
类型:
- Minor GC:通常很快,对新生代进行回收,STW时间较短。
- Major GC 或 Full GC:涉及整个堆的回收,STW时间较长,对性能的影响也更大。
-
并发收集:一些垃圾回收器如CMS(Concurrent Mark-Sweep)和G1(Garbage-First),通过并发标记和清除阶段减少STW时间。
-
低延迟收集器:例如ZGC和Shenandoah,它们通过并发处理大部分GC阶段,极大地减少了STW事件。
-
调优:通过调整JVM参数和选择合适的垃圾回收器,可以优化STW事件,减少其对应用程序性能的影响。
-
监控:通过监控工具,如JConsole或VisualVM,可以观察STW事件和持续时间,以评估垃圾回收对性能的影响。
-
应用设计:应用程序设计时,应考虑到STW的影响,例如,避免在性能敏感的路径上进行长时间的GC。
STW是垃圾回收的一个挑战,现代JVM通过各种策略和算法来减少STW的影响,以提供更平滑的应用程序性能。
垃圾收集算法
标记-清除(Mark-Sweep)算法
标记-清除算法(Mark-Sweep)是一种基础的垃圾回收算法,如上图所示,它通过以下两个主要步骤来回收内存中的垃圾对象:
-
标记阶段:算法从根集合(GC Roots)开始,使用可达性分析法遍历所有可达对象,并将这些存活对象进行标记。
-
清除阶段:算法再次遍历内存区域,这次是为了识别那些未被标记的对象,即那些不再被引用的垃圾对象,并将它们清理掉,从而释放内存空间。
这种算法的优点在于逻辑简单,易于实现,但它也有明显的缺点,如上图回收后JVM内存图,会产生内存碎片问题:由于对象是逐个被清理的,这可能导致内存中出现许多小的空闲区域,也就是JVM内存碎片。内存碎片过多时,当程序需要分配较大的连续内存块时,可能无法找到足够的空间,即便总的空闲内存是足够的。这种情况可能导致提前触发新一轮的垃圾收集,影响程序性能。
复制(Copying)算法

复制算法(Copying)是在标记清除算法上演化而来的,用于解决标记清除算法的内存碎片问题。如上图所示:它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当其中一块使用完,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样就保证了内存的连续性,逻辑清晰,运行高效。
优势:
- 简单高效:复制算法避免了标记-清除算法中内存碎片的问题,实现简单,运行高效3。
- 高吞吐量:由于只处理存活对象,所以效率较高,尤其适合新生代对象存活率低的情况1。
- 内存分配快速:复制算法完成后,空闲内存是连续的,分配内存时只需移动堆顶指针,非常快速。
缺点:
- 内存利用率降低:由于需要两个内存区域,实际使用的内存只有一半。
- 对象复制成本:需要复制存活对象,这会带来一定的性能开销。上述缺点让人
标记-清除-整理(Mark-Sweep-Compact)算法

标记-清除-整理(Mark-Sweep-Compact)算法是一种垃圾回收算法,这个算法分为三个阶段:
-
标记(Mark):在这个阶段,垃圾回收器遍历所有可达对象,从根对象开始,标记所有可达的对象。这意味着垃圾回收器会识别出所有仍然在使用中的对象,以便在后续阶段不会被错误地回收。
-
清除(Sweep):一旦标记阶段完成,垃圾回收器将遍历堆内存,清除所有未被标记的对象。这个阶段可能会留下内存碎片,因为对象是逐个被清除的,而不是成块地清除。
-
整理(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)提供了多种垃圾回收器,以适应不同的应用场景和性能要求。以下是一些常用的垃圾回收器及其特点:
- Serial GC:单线程,适合小内存和单核环境。
- ParNew GC:Serial的多线程版本,适合多核环境。
- Parallel Scavenge GC:追求吞吐量,适合后台处理。
- Serial Old GC:老年代单线程,使用标记-整理算法。
- Parallel Old GC:老年代多线程,与Parallel Scavenge配合。
- CMS GC:老年代并发收集,减少停顿时间,但可能产生内存碎片。
- G1 GC:堆分割为区域,追求低延迟和高吞吐量。
- ZGC:低延迟,几乎不牺牲吞吐量,适合大堆内存。
- Shenandoah:同样以低延迟为目标,由Red Hat开发。
每种垃圾回收器都有其特定的使用场景和优化目标。开发者可以根据应用程序的具体需求,选择合适的垃圾回收器来优化性能。随着Java技术的发展,新的垃圾回收器也在不断地被引入和优化。
小节
本章我们主要介绍了Java的垃圾机制,包括垃圾回收基本概念,重点介绍了垃圾回收机制中自动内存管理与垃圾收集算法。简短罗列了下常用见的垃圾回收器。下一篇我们见重点介绍各个垃圾回收器的特定、及适用的常见。
最后还是提一个小问题:你们线上JVM的参数是什么,使用的是什么垃圾回收器呢?
相关文章:
JVM专题十:JVM中的垃圾回收机制
在JVM专题九:JVM分代知识点梳理中,我们主要介绍了JVM为什么采用分代算法,以及相关的概念,本篇我们将详细拆分各个算法。 垃圾回收的概念 垃圾回收(Garbage Collection,GC)确实是计算机编程中的…...
MySQL入门学习-索引.创建索引
索引是 MySQL 中用于加速查询的一种数据结构。它通过在表的列上创建索引来加快数据的检索速度。 一、索引的概念 索引类似于书的目录,可以快速定位到表中的数据。当在表中的列上创建索引后,MySQL 会根据索引列的值对数据进行排序,并建立一个…...
ChatGPT智能对话绘画系统 带完整的安装源代码包以及搭建教程
系统概述 ChatGPT 智能对话绘画系统是一款集智能语言处理和绘画创作于一体的综合性系统。它利用了深度学习和自然语言处理技术,能够理解用户的意图和需求,并通过与用户的交互,生成富有创意的绘画作品。该系统的核心是一个强大的人工智能模型…...
巴中市红色旅游地管理系统
摘 要 随着红色旅游的兴起,越来越多的人开始对巴中市的红色旅游地产生兴趣。巴中市作为中国革命的重要发源地之一,具有丰富的红色旅游资源。然而,目前巴中市红色旅游地的管理仍然存在许多问题,如信息不对称、资源利用效率低等。为…...
ROS2从入门到精通2-2:详解机器人3D可视化工具Rviz2与案例分析
目录 0 专栏介绍1 什么是Rviz2?2 Rviz2基本界面3 Rviz2基本数据类型4 数据可视化案例4.1 实例1:显示USB摄像头数据4.2 实例2:显示球体 0 专栏介绍 本专栏旨在通过对ROS2的系统学习,掌握ROS2底层基本分布式原理,并具有…...
国企:2024年6月中国铁路相关招聘信息,6.27截止
中国铁路济南局集团有限公司2024年度 招聘普通高校本科及以上学历毕业生公告(三) 中国铁路济南局集团有限公司根据企业发展需要,拟招聘普通高等院校本科及以上学历毕业生,现将有关事项公告如下: 一、招聘计划 本次招聘岗位均为生产一线操作技能岗位,具体岗位、专业要求…...
React+TS前台项目实战(十九)-- 全局常用组件封装:带加载状态和清除等功能的Input组件实现
文章目录 前言Input组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天我们来封装一个input输入框组件,并提供一些常用的功能,你可以选择不同的 尺寸、添加前缀、显示加载状态、触发回调函数、自定义样式 等等。这些功能在这个项目中…...
php composer 报错
引用文章: Composer设置国内镜像_composer 国内源-CSDN博客 php composer.phar require --prefer-dist yiidoc/yii2-redactor "*" A connection timeout was encountered. If you intend to run Composer without connecting to the internet, run the …...
数据安全如何防护?迅软加密软件保护企业数据资产
前言:加密软件是一种重要的工具,可以帮助企业保护其数据资产的安全。通过使用加密算法,加密软件可以将敏感数据转化为无法理解的密文,只有授权的用户才能解密并访问这些数据。 一、迅软加密软件保护企业数据资产的关键方面 1、数…...
Android 11 ,默认授予预置应用/APK 需要的权限,解决permission denied for window type 2003 问题。
写这篇文章的原因是解决了一个APP闪退的问题,闪退的原因是插拔U盘时,注册的广播接收者接收到广播需要弹出一个Dialog询问是否需要打开U盘,这个Dialog设置的是系统级别悬浮窗,没有这个权限,报错导致闪退,下面…...
RabbitMQ(消息队列)
RabbitMQ 它是消息中间件,是在消息的传输过程中保存消息的容器,实现应用程序和应用程序之间通信的中间产品。目前主流消息队列通讯协议是AMQP(二进制传输,支持多种语言)、JMS(HTTP传输,只支持J…...
LeetCode-数组/回溯-No40组合总和II
题目: 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次 。 注意:解集不能包含重复的组合。 示例 1: 输入: ca…...
直接调用 Java 线程的 run() 方法会发生什么?
文章目录 前言回顾run() 方法 vs start() 方法run()方法start()方法 直接调用 run() 方法的影响直接调用 run() 方法调用 start() 方法 示例解析结论个人简介 前言 在Java中,多线程编程是一个重要的概念,尤其是在处理并发任务时。线程是Java中实现多线程…...
计算机毕业设计Thinkphp/Laravel学生考勤管理系统zyoqy
管理员登录学生考勤管理系统后,可以对首页、个人中心、公告信息管理、年级管理、专业管理、班级管理、学生管理、教师管理、课程信息管理、学生选课管理、课程签到管理、请假申请管理、销假申请管理等功能进行相应操作,如图5-2所示。学生登录进入学生考勤…...
3浏览器安全
上一篇👉: 浏览器渲染原理 浏览器安全涉及多方面的威胁与防护,其中XSS(跨站脚本攻击)与CSRF(跨站请求伪造)是最常见的两类安全问题,而中间人攻击与网络劫持也是不容忽视的安全隐患。下面是对这…...
昇思25天学习打卡Day01
实验结果 心得体会 趁着假期,跟谁官方实战营开始系统学习MindSpore深度学习框架。昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标。其中易开发表现为API友好,调试难度低;高效执行包括…...
Python-爬虫 下载天涯论坛帖子
为了爬取的高效性,实现的过程中我利用了python的threading模块,下面是threads.py模块,定义了下载解析页面的线程,下载图片的线程以及线程池 import threading import urllib2 import Queue import re thread_lock threading.RL…...
创建github个人博客
文章目录 安装Hexo安装git安装Node.js安装 Hexo git配置SSH key配置ssh 搭建个人博客新建博客生成静态网页 本文主要参考 【保姆级】利用Github搭建自己的个人博客,看完就会 安装Hexo 参考官方文档:https://hexo.io/zh-cn/docs/ Hexo 是一个快速、简洁且…...
【五子棋game】
编写一个五子棋游戏程序可以分为几个步骤:设计棋盘、定义规则、实现人机交互、判断胜负。下面是一个简化的五子棋游戏程序示例,使用Python语言编写。 首先,我们需要一个棋盘。可以使用一个二维数组来表示棋盘,其中0表示空位&#…...
从入门到精通:使用Python的Watchdog库监控文件系统的全面指南
从入门到精通:使用Python的Watchdog库监控文件系统的全面指南 引言Watchdog库概述核心组件工作原理 快速开始:设置Watchdog安装Watchdog创建一个简单的监控脚本设置和启动Observer 事件处理:如何响应文件系统的变化基本事件处理处理复杂的场景…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
【题解-洛谷】P10480 可达性统计
题目:P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M,接下来 M M M 行每行两个整数 x , y x,y x,y,表示从 …...

