JVM(5)

垃圾回收相关

垃圾收集器

警告:纯八股文!

如果说上面我们讲的收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体体现.

垃圾收集器的作用:垃圾收集器是为了保证程序能够正常,持久运行的一种技术,它是将程序中不用的死亡对象也就是垃圾对象进行清除,从而保证新的对象能够正常申请到内存空间.

垃圾回收器和垃圾回收算法的关系:

垃圾回收器是一种负责自动管理内存的软件组件,它负责在程序运行时识别和回收不再使用的内存(即垃圾),以便将内存重新分配给程序的其他部分.垃圾回收器实现了垃圾回收算法,这些算法决定了如何识别和回收垃圾.

1.垃圾回收器是实现垃圾回收算法的具体实体或组件,它是负责执行垃圾回收算法的执行者.

2.垃圾回收算法是一组规则和策略.用于确定哪些内存被视为垃圾,并在何时回收这些内存.

3.垃圾回收器通过调用和执行垃圾回收算法来实现内存管理.它负责在适当时机进行垃圾回收.并选择适当回收垃圾回收算法来回收内存.不同的垃圾处理器能实现不同的垃圾回收算法,以满足不同场景的需求.

以下这些收集器是HotSpot虚拟机伴随着不同版本推出的重要的垃圾收集器:

上图展示了7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用. 所处的区域,表示它是属于新生代收集器还是老年代收集器.再讲具体的收集器之前我们先来明确三个概念:

并行:指多条垃圾收集线程并行工作,用户线程仍处于等待状态.

并发:指用户线程和垃圾回收线程同时执行(不一定并行,可能会交替执行),用户程序继续执行,而垃圾收集程序在另外一个CPU上.

吞吐量:就是CPU用于运行用户代码的时间与CPU总消耗时间的比值.

吞吐量=运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)

例如:虚拟机总共运行了100分钟,其中垃圾收集花掉1分钟,那么吞吐量就是99%.

为什么会有这么多的垃圾收集器?

JVM有多种垃圾收集器,是因为不同的应用场景和需求可能需要不同的垃圾回收算法和策略.这些垃圾回收器的存在是为了在不同情况下提供最佳性能和吞吐量,并满足应用程序要求.

1.应用场景多样化:不同类型的应用程序具有不同的内存使用模式和性能要求.例如,一些应用可能需要低延迟,而另一些应用可能更注重吞吐量.因此需要不同类型的垃圾收集器来满足需求.

2.内存使用模式的不同:一些应用程序可能会生成大量短期对象,不同的垃圾收集器能针对这些不同的内存使用方式优化.

3.硬件和操作系统的不同:不同的硬件平台和操作系统可能对垃圾收集器产生不同的影响.因此存在多种垃圾回收器可以在不同的硬件和操作系统环境下提供最佳的性能.

4.持续的研究,更进,历史发展:自从有了Java语言就有了垃圾收集器,这么多垃圾收集器其实是历史发展的产物.最早的垃圾回收器为Serial,也就是串行执行的垃圾收集器,Serial Old为串行的老年代收集器,而随着时间的发展,为了提升更高的性能,于是就有了Serial多线程版的垃圾回收器ParNew.后来人们想要更高吞吐量的垃圾收集器,吞吐量是指单位时间内成功回收垃圾的数量,于是就有了吞吐量优先的垃圾收集器Parallel Scavenge(吞吐量优先的新生代垃圾收集器)和Parallel Old(吞吐量优先的老年代垃圾收集器).随着技术的发展后来又有了CMS垃圾收集器,CMS可以兼顾吞吐量和以获取最短回收停顿时间为目标的收集器,在JDK1.8(包含)之前BS系统的主流垃圾收集器,而在JDK1.8之后,出现了第一个既不完全属于新生代也不完全属于老年代的垃圾收集器G1,G1提供了基本不需要停止程序就可以收集垃圾的技术.

下面我们来看每种垃圾收集器的具体介绍:

CMS收集器(老年代收集器,并发GC)

特性:CMS收集器是一种以获取最短回收停顿时间为目标的收集器.目前很大一部分的Java应用几种在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,给用户带来较好的体验.CMS收集器就非常符合这类应用的需求.

CMS收集器是基于"标记-清除"算法实现的,它的运作过程较为复杂,整个过程分为四个步骤:

初始标记:初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,需要"Stop the world".("Stop the world"是指在垃圾收集的过程当中,应用程序的所有线程都会停止执行,这样垃圾收集器可以独占地执行垃圾收集操作.在停止的过程中,所有的用户线程都会暂停,包括应用程序的业务逻辑和其它的并发操作.这种暂停时间是可预测的,但是会对系统的响应时间和吞吐量产生影响.)

并发标记:并发标记阶段就是进行Roots Tracing的过程.

重新标记:重新标记阶段是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象标记记录,这个阶段的停顿时间一般会比初始标记阶段稍微长一些,但远比并发标记的时间短,仍然需要"Stop the world".

并发清除:并发清除阶段会清除对象.

由于整个过程中耗时最长的并发标记和并发清除过程收集器线程可以与用户线程一起工作,所以,从整体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的.

优点:

CMS是一款优秀的收集器,它的主要优点在名字上已经体现出来了:并发收集,低停顿 

缺点:

CMS收集器对CPU资源非常敏感. 其实,面向并发设计的程序都对CPU资源比较敏感.在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程(或者CPU资源)而导致应用程序变慢,总吞吐量会降低.  CMS默认启动的回收线程数是(CPU数量+3)/4.也就是当CPU在4个以上时,并发回收时垃圾收集线程不少于25%的CPU资源.并且随着CPU数量的增加而下降.但是当CPU不足4个(譬如2个)时,CMS对用户程序的影响就可能变得很大.

CMS收集器无法处理浮动垃圾,可能会出现"Concurrent Mode Failure"失败而导致另一次Full GC的产生.由于CMS并发清理阶段用户线程还在运行着,伴随程序运行字眼就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC再清理掉. 这一部分就叫做"浮动垃圾".也是由于在垃圾回收阶段用户线程还需要运行,那也就还需要预留有足够的内存空间给用户线程使用,因此CMS收集器不能像其他收集器那样等到老年代几乎完全被填满了再进行收集,需要预留一部分空间提供并发收集时的程序运作使用.要是CMS运行期间预留的内存无法满足程序需要,就会出现一次"Concurrent Mode failure"失败,这是虚拟机将启动后备预案:临时启动Serial Old收集器来重新进行老年代的垃圾收集,这样停顿的时间就很长了.

CMS收集器会产生大量空间碎片

CMS是一款基于"标记-清除"算法实现的收集器,这意味着收集结束时会有大量空间碎片的产生.空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC.

G1收集器(唯一一款全区域的垃圾回收器)

G1垃圾收集器是用在heap memory很大的情况下, 把heap划分为很多很多的region 块, 然后并行的对其进行垃圾回收.

G1垃圾收集器在清除实例所占用的内存空间后,还会做内存压缩.

G1垃圾收集器回收region的时候基本不会STW,而是基于most garbage优先回收(整体来看是基于"标记-整理"算法, 从局部(两个region之间)基于"复制"算法)的策略来对region进行垃圾回收的.无论如何,G1收集器采用的算法都意味着一个region有可能属于Eden,Survivor或者Tenured内存区域.图中的E表示改region属于Eden内存区域,S属于Survivor内存区域,T属于Tenured内存区域.图中空白的表示未使用的内存空间.G1垃圾收集器还增加了一种新的内存区域,叫做Humongous内存区域,如图中的H块.这种内存区域主要用于存储大的对象-即大小超过一个region大小的50%对象.

 

年轻代垃圾收集

在G1垃圾收集器中,年轻代的垃圾回收过程使用复制算法,把Eden区和Survivor区的对象复制到新的Survivor区域.

如下图:

 

老年代垃圾收集

对于老年代上的垃圾收集,G1垃圾收集器也分为4个阶段,基本跟CMS垃圾收集器一样,但略有不同.

初始标记阶段-同CMS垃圾收集器的初始标记阶段一样,G1也需要暂停应用程序的执行,它会标记从根对象出发,在根对象的第一层孩子节点中标记所有可达的对象.但是G1的垃圾收集器的初始标记是跟minor gc一同发生的. 也就是说,在G1中,你不用像CMS那样,单独暂停应用程序来进行初始标记阶段,而是在G1触发minor gc的时候一并将老年代的初始标记给做了 

并发标记阶段-在这个阶段G1做的事情跟CMS一样.但G1同时还做了一件事情,就是如果在并发标记阶段中,发现哪些Tenured region中对象的存活率很小或者基本没有对象存活,那么G1就会在这个阶段将其回收掉,而不用等到后面的clean up阶段.这也是Garbage First名字的由来.同时,在该阶段,G1会计算每个region的对象存活率,方便后面的clean up阶段使用.

最终标记-在这个阶段G1做的事情和CMS一样,但是采用的算法不同,G1采用一种叫STAB的算法能够在Remark阶段更快的标记可达对象.

筛选回收阶段-在G1中,没有CMS中对应的Sweep阶段.相反它有一个Clean up/Copy阶段,在这个阶段中,G1会挑选出那些对象存活率低的region进行回收,这个阶段也是与minor gc一同发生的,如下图所示:

G1是一款面向服务端应用的垃圾收集器.HotSpot开发团队赋予它的使命是未来可以替换掉JDK1.5中发布的CMS收集器.如果你的应用追求低停顿,G1可以作为选择;如果你的应用追求吞吐量,G1并不带来明显的好处.

总结:一个对象的一生

 一个对象的一生:我是个普通的Java对象,我出生在Eden区,在Eden区我还看到了和我长得很像的小兄弟,我们在Eden区中玩了挺长时间.有一天Eden区的人实在是太多了,我就被迫去了Survivor区的"From"区(s0区),有时候在Survivor的"To"区(s1区),居无定所.知道我18岁的时候,爸爸说我成人了,该去社会上闯闯了.于是我去了老年代那边,老年代里,人很多,并且年龄都挺大的,我在这里也认识了很多人.在老年代里,我生活了很多年(每次GC加一岁)然后被回收了.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Godot自定义控件样式语法解析

前言 本篇原始文章写于2023年8月7日,存储在我的语雀文档中。但是语雀分享有诸多不便,为了让更多Godoter更轻松的搜到和看到,就转过来了。 这个项目我上传了Github,后续会贴上链接。 概述 Godot控件体系存在的问题之一就是样式无…

链表OJ刷题(二)

制作不易,三连支持一下呗!!! 文章目录 前言一、链表的回文结构二、相交链表三、链表中倒数第k个节点四、环形链表Ⅰ和Ⅱ总结 前言 一、链表的回文结构 链表的回文结构_牛客题霸_牛客网 这里我们需要先了解一下什么叫做回文&#…

Rocky Linux 运维工具 dnf

一、dnf的简介 dnf​是用于在基于RPM包管理系统的包管理工具。用户可以通过 ​yum​来搜索、安装、更新和删除软件包,自动处理依赖关系,它是yum的继任者,旨在提供更快速、更现代化的软件包管理体验。。 二、dnf 的参数说明 序号参数描述1in…

django项目 法律法规管理系统

1.项目结构 2.项目需求 1.用户管理模块 2.数据采集模块 3.知识管理模块 4.智能匹配模块 5.个人收藏模块 6.数据分析模块 7.页面展示模块 3.知识点 1.智能匹配模块推荐算法的实现原理 TF (Term Frequency):词频,表示一个词在文档中出现的频…

LeetCode --- 长度最小的子数组(滑动窗口)

前言 滑动窗口算法是一种用于解决数组或者列表中子数组或者字串问题的方法,通常用于在给定数据上执行连续区间的操作,算法基本思想是维护一个固定大小或不定大小的窗口,通过移动窗口的起始位置和结束位置来遍历整个数据。在每个窗口位置&…

重拾前端基础知识:JavaScript

重拾前端基础知识:JavaScript 前言使用JavaScript输出语法运算符条件语句循环数据类型字符串数字数组对象日期函数 数学正则表达式异常处理类集合模块JSON闭包异步调试DOM(文档对象模型)事件事件监听器表单 BOM(浏览器对象模型&am…

【Linux杂货铺】调试工具gdb的使用

目录 🌈前言🌈 📁背景介绍 📁 使用 list [行号] / [函数名] run/r break/b [行号] / [函数名] info break disable break enable break delete break [断点编号] next/n step/s continue/c finish print/p [变量…

旧的Spring Security OAuth已停止维护,全面拥抱新解决方案Spring SAS

Spring Authorization Server 替换 Shiro 指引 背景 Spring 团队正式宣布 Spring Security OAuth 停止维护,该项目将不会再进行任何的迭代 目前 Spring 生态中的 OAuth2 授权服务器是 Spring Authorization Server 已经可以正式生产使用作为 SpringBoot 3.0 的最新…

Redis--事务机制的详解及应用

Redis事务的概念: Redis事务就是将一系列命令包装成一个队列,在执行时候按照添加的顺序依次执行,中间不会被打断或者干扰,在执行事务中,其他客户端提交的命令不可以插入到执行事务的队列中,简单来说Redis事…

Springboot接口参数校验

在设计接口时我们通常需要对接口中的非法参数做校验,以降低在程序运行时因为一些非法参数而导致程序发生异常的风险,例如登录的时候需要校验用户名密码是否为空,创建用户的时候需要校验邮件、手机号码格式是否准确。如果在代码中对接口参数一…

AOP案例(黑马学习笔记)

需求 需求:将案例中增、删、改相关接口的操作日志记录到数据库表中 ● 就是当访问部门管理和员工管理当中的增、删、改相关功能接口时,需要详细的操作日志,并保存在数据表中,便于后期数据追踪。 操作日志信息包含: ●…

基于HT32的智能家居demo(蓝牙上位机)

参加合泰杯作品的部分展示,基于HT32的智能家居,这里展示灯光的相关控制,是用蓝牙进行的数据透传,参考了一些资料,美化封装了一下之前的上位机界面。 成果展示 点击主界面的蓝牙设置,进行连接,下…

Android和Linux的嵌入式开发差异

最近开始投入Android的怀抱。说来惭愧,08年就听说这东西,当时也有同事投入去看,因为恶心Java,始终对这玩意无感,没想到现在不会这个嵌入式都快要没法搞了。为了不中年失业,所以只能回过头又来学。 首先还是…

编码规则转换

思考: 如何将一个机内码转换为区内码? 只要将机内码减去 A0A0 就可以啦 如果只让我们用加法器来解决呢? 注意我们的数据占用了 32 位,如果想用补码进行减法运算的话,符号位怎么办??&#xf…

了解Spring中Bean:配置与作用域

作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共…

Linux和Windows集群中部署HTCondor

目录 1、集群架构 2、HTCondor版本 3、Linux系统安装 3.1、HTCondor安装 3.2、中央管理节点配置 3.3、其他节点配置 4、Windwos系统安装 5、安全配置 6、参考 1、集群架构 操作系统IP地址1*Ubuntu22.04192.168.1.742Ubuntu22.04192.168.1.603Ubuntu22.04192.168.1.6…

python3装饰器

装饰器 它允许你修改函数或类的行为,而不更改其源代码。实质上,装饰器是接受另一个函数作为参数并返回一个包装原始函数的新函数。这样,你可以在不修改原始函数的情况下,添加一些额外的功能或逻辑。 def time_cost(func):"…

Java 数组(详细)

目录 一、数组的概述 1. 数组的理解: 2. 数组相关的概念: 3. 数组的特点: 4. 数组的分类: 5.数据结构: 二、一维数组 1. 一维数组的声明与初始化 2. 一维数组元素的引用: 3. 数组的属性&#xff1…

期货开户金融期货的种类

金融期货概念及其种类有哪些?期货种类分为商品期货、金融期货、和期货期权。金融期货是期货的其中一个种类,它是以证券;货币、汇率,利率等金融产品作为买卖标的的期货品种。金融期货交易产生于本世纪70年代的美国市场,…

项目解决方案: 实时视频拼接方案介绍(中)

目 录 1.实时视频拼接概述 2.适用场景 3.系统介绍 4. 拼接方案介绍 4.1基于4K摄像机的拼接方案 4.2采用1080P平台3.0 横向拼接 4.2.1系统架构 4.2.2系统功能 4.2.3方案特色 4.2.4适用场景 4.2.5设备选型 4.3纵横兼顾,竖屏拼接 4.3.1系统…