当前位置: 首页 > news >正文

深入学习JVM —— GC垃圾回收机制

前言

        前面荔枝已经梳理了有关JVM的体系结构和类加载机制,也详细地介绍了JVM在类加载时的双亲委派模型,而在这篇文章中荔枝将会比较详细地梳理有关JVM学习的另一大重点——GC垃圾回收机制的相关知识,重点了解的比如对象可达性的判断、四种回收算法、分代回收机制的流程和区域划分。希望对有需要的小伙伴有帮助~~~~


文章目录

前言

一、基本概念

1.1 Java中的引用类型 

1.2 垃圾回收区域

1.3 判断对象可回收的方法

1.3.1 引用计数法

1.3.2 可达性分析法

二、JVM中的垃圾回收算法

2.1 标记——清除算法

2.2 标记——复制算法

2.3 标记——整理算法

三、分代回收机制

3.1 垃圾回收的类型

3.2 空间结构与区域划分

3.3 跨代引用

总结


一、基本概念

        GC(Carbage Collection)又称为垃圾回收器,我们知道一个对象在其生命周期结束的时候是会被销毁掉的,在Java中对象的销毁时不需要开发者去显示调用的,而是交给Java虚拟机中的垃圾回收器来回收。Java中提供了多种垃圾回收器,而在JVM中会一直维护一个垃圾回收线程,通常该线程只有在堆内存不足或者是JVM空闲的时候才会触发执行,将他们添加到要回收的集合中并进行回收。

GC监控时机 

        对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。

1.1 Java中的引用类型 

Java中的引用类型有四种,分别是:强引用、弱引用、软引用和虚引用。Java中的默认声明其实就是强引用。

//强引用
//强引用所关联的对象始终不会被垃圾回收机制回收
String str
Object obj = new Object();//软引用
//内存不足的时候才会回收软引用所关联的对象
//软引用是通过java.lang.ref.SoftReference
buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);//弱引用
//无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收
//java.lang.ref.WeakReference 来表示弱引用
byte[] buff = new byte[1024 * 1024];
WeakReference<byte[]> sr = new WeakReference<>(buff);//虚引用
//虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收
//用 PhantomReference 类来表示
  • 强引用:发生 gc 的时候不会被回收,即使内存不足也不会回收而是抛出异常,如果想中断强引用于对象之间的联系,可以给引用赋值为null,这样对象就可以被回收了。
  • 软引用:有用但不是必须的对象,在发生内存溢出之前会被回收。
  • 弱引用:有用但不是必须的对象,在下一次GC时会被回收。
  • 虚引用:无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知。

1.2 垃圾回收区域

         在上一篇文章JVM的体系架构中我们了解了JVM的内存结构,其中讲到了JVM内存结构中的栈区中的基本类型数据是不会被垃圾回收机制给回收的,而是在超出其作用范围自动销毁滴。其实JVM中的GC机制主要是回收堆区和方法区内的基本数据和对象。

1.3 判断对象可回收的方法

在GC垃圾回收机制中,当对象没有引用了或者方法不可达就可以判断该对象可以回收,即垃圾回收线程可以将该对象加入回收集合了,具体的判断对象可达性的方法如下: 

1.3.1 引用计数法

为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收,这种方法实现起来比较简单。

缺点:无法回收相互引用的对象。

1.3.2 可达性分析法

        可达性分析法又被称为根搜索法,用来判断对象是否存活。从GC机制的某一个根节点触发开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的。

可作为根节点的对象:

  • 在虚拟机栈帧中引用的对象,例如线程调用方法时,使用或产生的参数、局部变量、临时变量等。
  • 在方法区中,类的引用类型静态变量或常量;
  • 在本地方法栈中的JNI引用的对象;
  • 在JVM内部的对象,例如基本数据类型的Class对象,一些常驻的异常对象(NullPointExcepiton),系统类加载器等;
  • 所有synchronized同步锁的持有对象;
  • 反映JVM内部情况的JMXBean、JVMTI注册的回调、本地代码缓存等。

二、JVM中的垃圾回收算法

JVM中的垃圾回收算法主要有四种,其中按回收策略来说应该分为两类:分代回收和局部回收。我们先来梳理局部回收的三种回收算法:

2.1 标记——清除算法

        简单描述该方法就是标记出所有的存活对象,再扫描整个空间中未被标记的对象进行垃圾清除(回收)。标记 - 清除算法由于回收后没有进行整理的操作,所以会存在内存空间碎片化的问题,可能会导致后续产生的对象不能找到可利用的空间这个问题。

2.2 标记——复制算法

        常规的复制算法就是将内存分为两块大小相同的空间,但其中的一块内存用完后就会将存活的对象拷贝到另一块内存中,之后再将原空间进行一次性清理,这个方法虽然效率高但却是以牺牲内存空间为代价的。标记-复制算法在这个基础之上对其进行了优化,不再是通过1:1的比例来分配内存空间,而是按照8:1:1来分配内存空间的,即将内存空间的80%作为Eden空间,剩下的20%分成两个10%的Survivor空间。把Eden和其中一块Survivor空间中存活的对象,复制到另一块空闲的Survivor空间,然后直接把Eden和使用过的那块Survivor空间清理掉。

需要注意的是:

        目前主流的使用分代回收机制的Java虚拟机,都是使用标记-复制算法来作为新生代的回收算法。它非常适合用在新生代这种回收率极高的场景,这样的场景下,复制算法浪费的空间几乎可以忽略不计。效率高,且内存不会有碎片化的问题。 

分配担保机制

        极端情况下可能会出现超过10%的对象存活,分配担保机制就是为了保证当出现这种情况时,有其他内存空间来存放存活的对象。通常这个“担保人”是老年代,当存活的对象超过Survivor空间大小时,这些存活的对象会忽略年龄,直接进入老年代里。  

2.3 标记——整理算法

        在前面我们了解到标记-清除算法的缺点就是会产生内存碎片,不适合哪些需要大量连续内存空间的场景,而标记-整理算法就是在其基础之上,增加了整理这个操作来解决内存空间碎片化的问题

算法流程

        首先标记出所有的存活对象,但在清除之前会先进行整理,把所有存活的对象往内存空间的左边移动,然后清理掉存活对象边界以外的内存,即完成了清除的操作。标记-整理 算法是在 标记-清除 算法之上,又进行了对象的移动排序整理,因此成本更高,但却解决了内存碎片的问题。上面的几种算法比较适合于老年代中的对象回收。


三、分代回收机制

接着我们来看看分代回收算法,在介绍分代回收机制之前,我们需要明确两个分代假说,或者说是常识也行:

  • 弱分代假说:绝大多数对象都是朝生夕改的
  • 强分代假说:熬过越多次垃圾回收的对象就越难消亡

根据分代假说,既然绝大多数对象容易被垃圾回收,而留下的对象不易被回收,就可以对GC区域内对象进行分类,分为新生代和老年代。相比两个区域内的对象的特性,GC就不用每次都对老年代进行搜索标记,而仅需要搜索标记新生代所存放的内存空间即可。

3.1 垃圾回收的类型

  • Minor GC:只回收新生代对象存放的内存空间
  • Major GC:只回收老年代对象存放的内存空间,只有CMS收集器实现了Major GC
  • Full GC:回收整个堆区和方法区,相当于全盘扫描标记,效率低
  • Mixed GC:回收整个新生代和部分老年代。G1收集器实现了这个类型 

需要注意的是:在老年代里,触发GC,除了CMS和G1之外的其他收集器,大多数触发的其实是 Full GC。

3.2 空间结构与区域划分

我们知道在GC中一般将对象分为新生代(年轻代)和老年代(年老代),下面我们详细认识一下整个二者以及堆区和方法区的具体空间结构。

新生代:

绝大多数新创建的对象会被分配到新生代里,仅在该区域进行垃圾回收被称之为Minor GC。

老年代:

        对象在新生代周期中存活了下来的,会被拷贝到这里。通常情况下这个区域分配的空间要比新生代多。正是由于对象经历的GC次数越多越难回收,加上相对大的空间,一般发生在老年代的GC次数要比新生代少得多。这个区域触发的垃圾回收称之为:Major GC 或者 Full GC。

永久代

        是hotspot虚拟机的特有的概念,他不属于堆内存,是方法区的一种实现,各大厂商对方法区其实都有各自的实现。永久代一般存放jvm运行时需要的类,包含java库的类和方法,在触发full gc的情况下,永久代也会被进行垃圾回收。在JDK1.8之后,JVM使用元空间metaspace来取代永久代,最大区别是元空间中的数据是储存在本地内存的。

空间结构

        一般来说呢,新生代的空间会被按照 8:1:1 的方式来进行划分为一个Eden空间和两个Survivor空间,这种设计是为了更好的适配新生代对象容易被回收的特点,同时也比较适合使用标记——复制算法来GC。那些经历了多次GC的对象一般都是从新生代的Eden到Survive空间,重复N次达到设定的阈值后才会到老年代空间里面,当然也有一些比较大的对象是直接到老年代空间里面的。

 

老年代区域GC耗时更长的原因:

  • 老年代中会有更比较大的对象,并且老年代的内存占比一般更大;
  • 老年代使用的是标记-整理算法,清理内存前会把存活的对象重新排序整理成连续的空间,成本更高

3.3 跨代引用

场景:新生代中的对象很有可能会被老年代里的对象所引用,当新生代触发GC的时候,只搜索新生代的区域明显是不够的,还得搜索老年代的对象是否引用了新生代中非 GC Roots 引用链上的对象,来确保正确性。 

解决方法 

        Java定义了一种名为记忆集的抽象的数据结构,用于记录存在跨区域引用的对象指针集合。大多数的虚拟机,都采用一种名为卡表(Card Table)的方式去实现记忆集,卡表由一个数组构成,每一个元素都对应着一块特定大小的内存区域,这块内存区域被称之为卡页(Card Page),每一个卡页,可能会包含N个存在跨区域引用的对象,只要存在跨区域引用的对象,这个卡页就会被标识为1。当GC发生的时候,就不需要扫描整个区域了,只需要把这些被标识为1的卡页加入对应区域的 GC Roots 里一起扫描即可。


总结

        这篇文章结束,荔枝有关JVM的初步学习就要告一段落啦,这篇文章主要还是大体上了解了JVM的垃圾回收机制中的一些空间结构和区域划分,以及不同时期的对象在堆空间中存储的区域和相关的回收算法。总的来说通过这几篇文章应该就答题了解的差不多了,接下来荔枝就要开始看项目和继续学习一些中间件了哈哈哈,大家一起加油啦~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

相关文章:

深入学习JVM —— GC垃圾回收机制

前言 前面荔枝已经梳理了有关JVM的体系结构和类加载机制&#xff0c;也详细地介绍了JVM在类加载时的双亲委派模型&#xff0c;而在这篇文章中荔枝将会比较详细地梳理有关JVM学习的另一大重点——GC垃圾回收机制的相关知识&#xff0c;重点了解的比如对象可达性的判断、四种回收…...

Centos7.6 + Apache Ranger 2.4.0编译(docker方式)

目录 一、Ranger简介 1、组件列表 2、支持的数据引擎服务 二、主机环境准备 1、关闭防火墙 2、关闭SELINUX 3、安装docker 4、下载Ranger源码包 5、下载Maven安装包 三、编译Ranger源码 1、修改官方包中的build_ranger_using_docker.sh 2、运行脚本编译 3、编译检…...

LVS-DR模式集群配置

四台虚拟机 node1&#xff1a;128 node2&#xff1a;135 RS端&#xff1a; node3&#xff1a;130 node4&#xff1a;132 [rootnode2 ~]# yum install -y ipvsadm #配置LVS虚拟IP&#xff0c;没有ifconfig命令则先安装 [rootnode2 ~]# yum install net-tools -y #配置VIP [root…...

【数据分析】pandas( 二)

目录 简介&#xff1a; 一&#xff0c;1.1来自Series字典或字典 1.2 来自ndarray或者列表的字典&#xff1a; 1.3来自结构化或记录数组; 1.4来自字典列表&#xff1a; 1.4来自元组的字典&#xff1a; 1.5 来自Series 二&#xff0c;代替构造函数&#xff1a; 2.1DataFram…...

ffmpeg工具实用命令

说明&#xff1a;ffmpeg是一款非常好用的媒体操作工具&#xff0c;包含了许多对于视频、音频的操作&#xff0c;有些视频播放器里面实际上就是使用了ffmpeg。本文介绍ffmpeg的使用以及一些较为实用的命令。 安装 ffmpeg是命令行操作的&#xff0c;不需要安装&#xff0c;可在…...

zabbix API笔记

博客园原文 python简单demo 输出id为111主机的主机群组信息 import requests import json request_headers {"Content-Type": "application/json"} zabbix_url "http://xxx.xxx.xxx.xxx:8080/zabbix/api_jsonrpc.php" get_hostgroup_from_h…...

[HDLBits] Mt2015 q4a

Module A is supposed to implement the function z (x^y) & x. Implement this module. module top_module (input x, input y, output z);assign z(x^y)&x; endmodule...

HarmonyOS NEXT,生命之树初长成

在不同的神话体系中&#xff0c;都有着关于生命之树的记载。 比如在北欧神话中&#xff0c;一株巨大的树木联结着九大世界&#xff0c;其被称为“尤克特拉希尔”Yggdrasill。在中国的《山海经》中&#xff0c;也有着“建木”的传说&#xff0c;它“有九欘&#xff0c;下有九枸&…...

PHPstudy配置伪静态步骤,tp5.1的框架

搜索mod_rewrite.so&#xff0c;然后去掉前面的#&#xff08;即放开注释&#xff09; 2.找到index.php 同级文件.htaccess&#xff08;没有就新建&#xff09; 这些是tp5.1自带的内容&#xff0c;把它注释掉&#xff0c;是错误的内容&#xff0c;添加下面的这段配置 #<If…...

LeetCode:Hot100的python版本

94. 二叉树的中序遍历...

rv1126更新rknpu驱动教学

测试平台&#xff1a;易佰纳rv1126 38板 查看板端版本-------------------------------------------------- 1&#xff1a;查看npu驱动版本 dmesg | grep -i galcore&#xff0c;可以看到版本为6.4.3.5 2&#xff1a;查看rknn-server版本 strings /usr/bin/rknn_server | g…...

[机器学习]线性回归模型

线性回归 线性回归&#xff1a;根据数据&#xff0c;确定两种或两种以上变量间相互依赖的定量关系 函数表达式&#xff1a; y f ( x 1 , x 2 . . . x n ) y f(x_1,x_2...x_n) yf(x1​,x2​...xn​) ​ 回归根据变量数分为一元回归[ y f ( x ) yf(x) yf(x)]和多元回归[ y …...

Vue基于php医院预约挂号系统_6nrhh

随着信息时代的来临&#xff0c;过去的管理方式缺点逐渐暴露&#xff0c;对过去的医院预约挂号管理方式的缺点进行分析&#xff0c;采取计算机方式构建医院预约挂号系统。本文通过阅读相关文献&#xff0c;研究国内外相关技术&#xff0c;开发并设计一款医院预约挂号系统的构建…...

2023-08-07力扣今日六题-不错题

链接&#xff1a; 剑指 Offer 04. 二维数组中的查找 题意&#xff1a; 一个二维矩阵数组&#xff0c;在行上非递减&#xff0c;列上也非递减 解&#xff1a; 虽然在行列上非递减&#xff0c;但是整体并不有序&#xff0c;第一行存在大于第二行的数字&#xff0c;第一列存在…...

Elasticsearch搜索出现NAN异常

原因分析 Elasticsearch默认的打分&#xff0c;一般是不会出现异常的之所以会出现NAN异常&#xff0c;往往是因为我们重新计算了打分&#xff0c;使用了function_score核心原因是在function_score中&#xff0c;出现了计算异常&#xff0c;比如 0/0,比如log1p(x),x为负数等 真…...

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(6)

1001 Count 当k在区间(1n)/2的左边时,如图,[1,k]和[n-k1,n]完全相同,所以就m^(n-k) 当k在区间(1n)/2的右边时,如图,[1,n-k1]和[k,n]完全相同,所以也是m^(n-k) 别忘了特判,当k等于n时,n-k为0,然后a1a1,a2a2,..anan,所以没什么限制,那么就是m^n AC代码&#xff1a; #includ…...

【JavaScript 】浏览器事件处理

1. 什么是浏览器事件? 浏览器事件是指在网页中发生的各种交互和动作,例如用户点击按钮、页面加载完成、输入框文本变化等。通过处理这些事件,可以编写相应的JavaScript代码来实现特定的功能和行为。 2. 常见的浏览器事件 以下是一些常见的浏览器事件及其用途的详细介绍: c…...

(力扣)用两个队列实现栈---C语言

分享一首歌曲吧&#xff0c;希望在枯燥的刷题生活中带给你希望和勇气&#xff0c;加油&#xff01; 题目&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#…...

使用 RediSearch 在 Redis 中进行全文检索

原文链接&#xff1a; 使用 RediSearch 在 Redis 中进行全文检索 Redis 大家肯定都不陌生了&#xff0c;作为一种快速、高性能的键值存储数据库&#xff0c;广泛应用于缓存、队列、会话存储等方面。 然而&#xff0c;Redis 在原生状态下并不支持全文检索功能&#xff0c;这使…...

[Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序

1.今天开发了一套服务程序&#xff0c;使用的是Odbc连接MySql数据库&#xff0c; 在我本机用VS打开程序时&#xff0c;访问一切正常&#xff0c;当发布出来装在电脑上&#xff0c;连接数据库时提示&#xff1a; [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天&#xff0c;今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案&#xff0c;它们不仅提供了优雅的设计思路&#xff0c;还能显著提升系统的性能…...