Java基础--->JVM(3)【垃圾回收】

news2024/11/14 21:39:27

文章目录

  • 垃圾回收(GC)
  • 什么内存需要回收(什么样的对象是垃圾)?为什么要进行垃圾回收?
  • 内存溢出和内存泄露的区别,如何解决
  • 分区收集思想 Minor GC、Major GC、Full GC
  • 垃圾回收相关算法
    • 引用计数算法(在现代的JVM中并没有被使用)
    • 可达性分析算法/根搜索算法
    • 对象的 finalization 机制
    • 垃圾回收阶段的算法
  • 垃圾回收器
    • 垃圾回收器分类
    • CMS垃圾回收器(Concurrent Mark Sweep 并发标记清除)
    • G1(Garbage-First)垃圾回收器

垃圾回收(GC)

无任何说明都是针对HotSpot虚拟机

好处:解放程序员,对内存管理更合理,自动化

不好的:对程序员管理内存的能力降低了, 解决问题能力变弱了, 不能调整垃圾回收的机制

​ 对于Java程序员来说,在虚拟机内存管理机制下,不需要像C/C++语言那样手动去垃圾回收操作,不容易出现内存泄漏和内存溢出等问题。但正是因为Java程序员吧内存控制权交给Java虚拟机,一旦出现内存方面泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会非常艰难。

​ 第一个使用自动垃圾回收的不是Java语言,

​ Java堆是垃圾收集器管理的主要区域,因此也成为GC堆(Garbage Collected Heap),从垃圾回收的角度来说,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆被划分了几个不同区域,这样我们就可以根据各个区域的特点选择合适的垃圾收集算法。

堆空间详解以及垃圾回收可以看—>Java内存区域详解

什么内存需要回收(什么样的对象是垃圾)?为什么要进行垃圾回收?

Java中的垃圾对象是指没有被任何引用变量所引用的对象。这些对象无法被访问,也无法被使用,因此它们占用内存空间而不被程序所使用,成为垃圾对象。如果不进行垃圾回收,内存迟早都会被消耗完,不断的分配内存空间而不进行回收,就像不停的生产生活垃圾而从来不进行打扫一样,垃圾回收也可以清除内存里的记录碎片,将这些碎片进行整理占用的内存移动到堆的一端,方便JVM将整理出的内存分配给新的对象(数组必须是连续空间)。

内存溢出和内存泄露的区别,如何解决

内存溢出指的是程序在申请内存时,由于没有足够的内存可用,而导致程序崩溃或者出现其他异常情况的现象。这通常是因为程序错误地使用了内存,例如未及时释放不需要的内存或者使用了太多内存资源,导致系统无法提供足够的内存来满足应用程序的需求。

内存泄漏指的是程序中存在一些对象或变量没有被垃圾回收器及时回收,导致这些对象一直占用着内存空间并最终耗尽可用内存的现象。通常是因为程序中存在不合理的设计或编码问题,例如忘记释放动态分配的内存、使用循环引用等等。还有就是打开了使用对象的东西,但是没有关闭,导致垃圾处理时认为对象处于运行状态,不会被回收处理,IOclosejdbc链接close没有关闭。

两者区别在于,内存泄漏是程序代码中存在的开发问题,内存溢出则是由于系统资源有限造成的结果。需要解决内存泄漏问题,通常需要审查代码并进行调试,而需要解决内存溢出问题,则需要考虑优化应用程序,增加可用内存资源,并可能需要进行代码重新设计,以便更有效地使用和释放内存。

分区收集思想 Minor GC、Major GC、Full GC

部分收集、整堆收集

  • 新生区收集(Minor GC/Yang GC): 只是新生区(Eden ,S0,S1)的垃圾收集 ,回收比较频繁
  • 老年区收集(Major GC/Old GC):只是对老年区的垃圾收集,回收的次数较少
  • 混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集
  • 整堆收集(Full GC):收集整个java堆和方法区的垃圾收集,尽量避免

垃圾回收相关算法

标记阶段

​ 作用:判断对象是否是垃圾对象,是否有引用指向对象

​ 相关的标记算法:引用计数算法和可达性分析算法

引用计数算法(在现代的JVM中并没有被使用)

在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就 +1;当引用失效时,计数器值就 -1 ;任何时刻计数器为 0 的对象就是不可能再被使用的。

//有个计数器来记录对象的引用数量
String s1 = new String("aaa");
String s2 = s1;  //有两个引用变量指向aaa对象
s2 = null; -1
s1 = null; -1

引用计数法原理简单,效率也很高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,主要原因是引用计数就很难解决对象之间相互循环引用的问题。

例如,存在两个对象objAobjB,他们都有字段instance,令objA.instance=objB;objB.instance=objA除此之外,这两个对象再无任何引用,实际上这两个对象已 经不可能再被访问,但是它们因为互相引用着对方,导致它们的引用计数都不为零,引用计数算法也就无法回收它们。

缺点:

需要维护计数器,占用空间,频繁操作需要事件开销

无法解决循环引用问题,多个对象之间相互引用,没有其他外部引用指向他们,计数器都不为0,不能回收,产生内存泄漏

可达性分析算法/根搜索算法

可达性分析算法是一种常用的内存管理算法,它的核心思想是从一组根对象(GCRoots)开始,通过遍历对象引用关系,确定哪些对象可以被访问到,哪些对象是不可访问的,然后把不可访问的对象标记为垃圾,最终回收这些不可访问的对象占用的内存空间。

可达性分析算法是当前主流的垃圾回收算法,由于它能够处理循环引用的情况,因此能够避免内存泄漏的问题,并且由于标记过程不需要对所有对象进行遍历,因此回收效率较高。

GC Roots 可以是哪些元素?

  • 在虚拟机栈中被使用的.
  • 在方法中存储的静态成员指向的对象
  • 在方法区中常量引用的对象
  • 作为同步锁使用的 synchronized
  • 在虚拟机内部使用的对象

对象的 finalization 机制

对象的 finalization 机制是一种内存管理模式,它允许程序在对象被垃圾回收之前执行特定的清理和释放操作。在Java中,finalize() 方法是用于实现对象的 finalization 机制的。

当一个对象变为垃圾之前,JVM会在内部自动调用其 finalize() 方法(如果该对象的 finalize() 方法未被重写,则不会执行任何操作),并在 finalize() 方法执行结束之后回收该对象。开发人员可以在 finalize() 方法中编写释放资源、关闭打开的文件、清除临时数据等操作,以便程序尽快回收不再使用的内存空间。

需要注意的是,finalize() 方法调用具有不确定性,即无法保证 finalize() 方法执行的时间、频率和顺序。因此,不应该在 finalize() 方法中执行太复杂或太耗时的操作,否则可能会导致垃圾回收的效率下降或者程序出现异常情况。

有了finalization机制的存在,在虚拟机中把对象状态分为3种:

  1. 可触及的 ,不是垃圾,与根对象连接的

  2. 可复活的 ,判定为垃圾了,但是还没有调用finalize(),(在finalize()中对象可能会复活)

  3. 不可触及的: 判定为垃圾了,finalize()也被执行过了,这种就是必须被回收的对象

垃圾回收阶段的算法

标记-复制算法

标记复制算法是一种垃圾回收算法,它在内存分配时将堆内存分为两部分,每次只使用其中一块,当这一块满时,将其中的存活对象复制到另一块空闲的空间,然后把原来的空闲空间全部清除,切换使用这个空间,如此反复执行,达到回收垃圾的目的。

优点: 减少内存碎片

缺点: 如果内存中多数对象存活,则需要复制的对象数量多,效率低.

适用场景:存活对象少,新生代适合使用标记复制算法
在这里插入图片描述

标记-清除算法

标记清除算法是一种垃圾回收算法,它在进行内存回收时,会先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记出所有仍然在使用中的对象,然后清除没有被标记的对象,释放它们所占用的内存空间。

清除不是真正的把垃圾对象清除掉,而是将垃圾对象地址维护到一个空闲列表中,后面有新对象到来时,覆盖掉垃圾对象即可。

优点: 标记清除算法具有简单、可行的特点,适用于长时间运行、堆内存分配较为稳定的场景

缺点:但由于清除过程需要扫描堆的所有内存块,如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,因此效率较低且可能会使剩余内存出现不连续的碎片化,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。在快速分配和释放内存的场景下,标记清除算法的效率会受到较大影响。

标记-压缩算法(标记-整理)

标记-整理算法:其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存,一般用于对于长时间运行的老年代堆空间进行回收操作。

优点: 标记压缩算法相较于标记清除算法来说,能够减少内存碎片,简化内存回收操作

缺点: 其实现效率通常较低,因为它需要花费额外的时间和空间来进行压缩操作,并且移动对象的操作也会带来额外的复杂性和开销。移动存活对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用程序才能进行。

在这里插入图片描述

总结

由以上三种算法可以看出:是否移动对象都存在弊端,移动的话内存回收更复杂,不移动则内存分配会更复杂。从垃圾收集的停顿时间来看,不移动对象停顿时间会更短,甚至可以不需要停顿,但是从整个程序的吞吐量来看,移动对象会更划算。

此外就出现了另一种解决方案:

  • 可以不在内存分配和访问上增加太大额外负担,做法是让虚拟机平时多数时间都采用标记-清除算法,暂时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配时,再采用标记-整理算法收集一次,以获得规整的内存空间

垃圾回收器

垃圾回收算法是方法论,垃圾回收器是内存回收的具体实现

​虽然我们对各个收集器进行比较,但是并非要选择一个最好的收集器,因为直到现在还没有最好的垃圾收集器出现,更没有万能的垃圾收集器,我们能做的就是根据具体应用场景选择适合自己的垃圾收集器

垃圾回收器分类

  • 按照线程数量分

    单线程垃圾回收器:Serial Serial old

    只有一个线程进行垃圾回收,适用于小型简单的适用场景,垃圾回收时,其他用户线程会暂停

    多线程垃圾回收器:Parallel

    多线程垃圾回收器内部提供多个线程进行垃圾回收,在多cpu情况下大大提升垃圾回收效率,但是同样也会暂停其他用户线程。

  • 按照工作模式分为

    独占式:垃圾回收线程执行时,其他线程暂停

    并行式:垃圾回收线程可以和用户线程同时执行

  • 按工作的内存区间

    年轻代垃圾回收器,老年代垃圾回收器

    垃圾回收器(GC)性能指标

    暂停时间(在垃圾回收过程中,其他线程暂停)

    吞吐量:运行用户代码的时间占总运行时间的比例

    垃圾收集开销: 垃圾收集所用时间与总运行时间的比例

    暂停时间: 执行垃圾收集时,程序的工作线程被暂停的时间

    内存占用:Java堆区域所占的内存大小

    快速: 一个对象从诞生到被回收所经历的时间

CMS垃圾回收器(Concurrent Mark Sweep 并发标记清除)

CMS垃圾回收器是一种面向服务器端应用程序的内存回收器。相较于其他垃圾回收器,CMS垃圾回收器采用并发的方式进行垃圾回收,以减少应用程序的暂停时间,提高程序的可用性和性能。 与其他垃圾回收器不同的是,它的垃圾回收过程并不是在暂停应用程序的情况下完成的,而是并发进行的,因此不会对应用程序的性能产生明显的影响。

CMS收集器是一种标记-清除算法,相较于前面几种垃圾收集器来说更为复杂,整个过程四个步骤

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

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

重新标记: 修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,暂停所有的其他线程,停顿时间比初始标记稍微长,但远远比并发标记阶段时间短。

并发清除:垃圾回收线程与用户线程并发(同时)执行 ,对为标记的区域进行垃圾对象的清除

优点:可以作到并发收集

弊端:使用标记清除算法,会产生内存碎片,并发执行影响到用户线程,无法处理浮动垃圾

三色标记:

​ 由于CMS有并发执行过程,所以在标记垃圾对象时有不确定性。

​ 所以在标记时,将对象分为三种颜色(3中状态)

​ 黑色: 例如GCRoots确定是存活的对象

​ 灰色:在黑色对象中关联的对象,其中还有未扫描完的,之后还需要再次进行扫描

​ 白色:与黑色,灰色对象无关联的,垃圾收集算法不可达的对象

标记过程:

​ 1.先确立GCRoots,把GCRoots标记为黑色

​ 2.与GCRoots关联的对象标记为灰色

​ 3.再次遍历灰色,灰色变为黑色,灰色下面有关联的对象,关联的对象变为灰色

​ 4.最终保留黑色,灰色,回收白色对象

可能会出现漏标,错标问题

G1(Garbage-First)垃圾回收器

G1是Java虚拟机中的一种新型、高效的垃圾回收器,它在JDK7中首次推出,是目前Java虚拟机中最受欢迎的垃圾回收器之一。

相比于传统的垃圾回收器,G1具有以下优点:

  1. 高效、可预测的垃圾回收:G1在堆内存分为多个区域,每个区域都会被扫描,并针对性的执行清理操作。因此,G1能够同时实现高效和可预测的垃圾回收。
  2. 系统吞吐量更高:相比于传统的垃圾回收器,G1在长时间的运行中系统吞吐量表现更加稳定,同时能达到更高的吞吐量。
  3. 更好的平均响应时间:G1在执行垃圾回收时不会导致长时间的停顿,这样可以获得更好的平均响应时间。
  4. 更少的内存消耗:G1将整个堆内存划分为多个区域,垃圾回收时只需要扫描需要回收的区域,因此可以减少不必要的内存消耗。

但是,与其它垃圾回收器相比,G1也有一些不足之处。比如G1需要更多的CPU和内存资源,可能会对应用程序的性能产生一定的影响。此外,在堆内存比较小的情况下,G1的表现也不够理想。

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

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

相关文章

如何搭建产品操作手册

对于企业来说,拥有一份完备的产品操作手册无疑是至关重要的。操作手册不仅是新员工学习产品使用及维护的重要参考,也是产品售后服务与客户支持的必备文件。在手册编写上,应清晰明了地介绍产品的功能、配置及故障排除等信息,使用户…

统计学下的假设检验

由于本人才疏学浅,再加上时间仓促,难免有疏漏之处,恳请批评指正. 1,预备知识 数理统计:以概率论为基础,研究如何有效的去搜集、整理、分析带随机性影响的数据 总体与样本:研究对象的全体就称为总体 样本&a…

VTK交互-vtkBoxWidget2

VTK交互Widget widget包含两个重要的组成部分:Interaction和Representation. Interaction是一些名叫vtk*Widget的类(比如vtkBoxWidget2)。它包含了交互的所有选项和事件处理。 Representation是显示并与之交互的一类对象,以名叫v…

origin 拟合计算酶的Kcat Km 值

origin拟合计算Kcat Km值 横坐标为底物浓度,纵坐标为反应速率 全选X 与Y坐标数据,然后选择菜单栏Analysis: Fitting: Nonlinear Curve Fit:Open Dialog 在Setting:Function Selection页面内的Category选择Pharmacology, Functi…

计算机网络基础知识(三)—— 什么是OSI七层模型?

文章目录 00 | 🛸发展史🛸01 | 🛸OSI七层参考模型🛸02 | 🛸OSI七层参考模型的信息流向🛸 OSI七层模型是Open Systems Interconnection Reference Model的缩写,是由国际标准化组织(IS…

vue3使用keep-alive组件,包含动态组件使用

vue3使用keep-alive组件,包含动态组件使用 本文目录 vue3使用keep-alive组件,包含动态组件使用组件不使用keep-alive组件中使用v-if切换component动态组件切换因注释导致的意外错误动态组件的使用完整示例 路由不使用keep-alive路由中使用keep-alive生命…

公司数字化转型,如何选择高效的知识管理工具?

随着企业数字化转型的加速,知识管理工具的重要性也日益凸显。好的知识管理工具可以帮助企业提高工作效率、降低成本、提高创新能力和竞争力。但是,市场上的知识管理工具繁多,如何选择高效的知识管理工具成为了企业面临的一大难题。本文将从以…

Jenkins 入门系列之Role-based Strategy配置Gitlab Group管理用户组

目录 背景步骤1. 安装插件2. 配置Gitlab Group3. 配置 Jenkins 授权策略4. 配置 Jenkins 角色与授权5. 验证 背景 版本 Jenkins Version:Jenkins 2.403Gitlab Version: Gitlab 15.6部署环境:群晖NAS Docker 部署JenkinsGitlab 上一篇文章Jenkins 入门…

HTML详解

HTML是什么 html是一门语言,所有的网页都是用它编写出来的。 他是一门超文本标记语言。可以定义图片,音频,视频等。由标签组成。 HTMl仅仅定义了网站的接口。 具体的表现还需要css来实现,也就是css让网页变得更加好看。 网页…

智能聊天机器人ChatGPT商业版

作为一个智能聊天机器人,我是由OpenAI开发的。目前,我的商业版需要通过OpenAI的合作伙伴计划进行许可和部署,以确保我被用于适当的商业用途。如果您对商业使用感兴趣,请联系OpenAI以获取更多信息。 智能聊天机器人是一种能够自…

如何优化golang gc

目录 一.理解GO GC机制 1.1GC的耗时 1.2堆大小对GC的影响 1.3GC算法 二 如何查看GC信息 2.1使用GODEBUG"gotrace1" 2.2 go tool trace 2.3 debug.ReadGCStats ​编辑2.4 runtime.ReadMemStats 三 GC优化技巧 2.1并发GC 一.理解GO GC机制 GO语言采用的是三…

学习网络安全的拦路虎!你遇到几个?

很多零基础的同学想要学习网络安全,前期会各种寻找学习资料。最后发现资料一大堆,但无从下手,于是千辛万苦收集的资料就去收藏夹吃灰了。开始学习的小伙伴们通常也会越学越迷茫,毕竟资料并不是完整的,而是东拼西凑出来…

Docker时区问题

背景 当前docker容器技术应用越来越广泛,但在启动容器后,容器内部的时间并不是东八区 Docker的基础镜像设置大多是UTC,也就是标准的UTC 时间,所以要简单的调整一下,变成中国标准时间CST(China Standard Time UTC8:0…

OpenCL编程指南-1.2OpenCL图形API

OpenCL与图形 OpenCL的出现是对GPCPU编程的一个响应。人们用GPU处理图形,并且开始使用GPU完成工作中的非图形部分。基于这种趋势,异构计算(已经存在很长时间)与图形发生冲突,因此迫切需要一个行业标准。 OpenCL一直与…

使用Onenote进行钓鱼攻击事件分析

以其中遇到的一个案例为例子进行展开分析: 1、使用钓鱼邮件文案.one文件附件 From: Bank Complaints <bankcomplaintshkmagov.com> Sent: Thursday, March 2, 2023 11:00 AMTo: Miles Mok XXXXSubject: [External Mail] xxxx Industry Development Survey Dear XXXX Lt…

SpringBoot+Canal+RabbitMQ实战

1. Canal简介 https://github.com/alibaba/canal 1.1 Canal工作原理 MySQL主备复制原理 MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events&#xff0c;可以通过 show binlog events 进行查看)MySQL slave 将 master 的 b…

中断-NVIC与EXTI外设详解(超全面)

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转STM32 &#x1f4ac;推荐一…

档案馆对于档案室档案库房内温度和湿度的控制要求

编辑搜图 请点击输入图片描述&#xff08;最多18字&#xff09; 01 纸质档案库的温湿度要求 用房名称温度&#xff08;℃&#xff09;相对湿度&#xff08;%&#xff09;纸质档案库14~2445~60 02 特殊档案库的温湿度要求 用房名称温度&#xff08;℃&#xff09;相对湿度&am…

Golang中的运算符

目录 运算符 算术运算符 代码案例&#xff1a; 关系运算符 代码案例&#xff1a; 逻辑运算符 代码案例&#xff1a; 位运算符 代码案例&#xff1a; 赋值运算符 代码案例&#xff1a; 其他运算符 运算符 算术运算符 Go语言中的算术运算符包括加、减、乘、除和取模…

【深入理解redis】数据结构

文章目录 动态字符串SDS字符串编码类型 intsetDictZipListZipList的连锁更新问题 QuickListSkipListRedisObjectStringListSet结构ZSETHash Redis 共有 5 种基本数据结构&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;…