关于JVM的垃圾回收GC的一些记录

目录

一、JVM内存区域划分

 二、从一个基本问题开始引入垃圾回收

三、GC作用的区域

三、如何确定一个对象是否可以被当成垃圾进行回收

(1)引用计数法

(2)可达性分析算法

(3)引用的类型

(3.1)强引用(Strong Reference)

(3.2)软引用(Soft Reference)

(3.3)弱引用(Weak Reference)

(3.4)虚引用(Phantom Reference)

(3.5)终结器引用(Final Reference)

(4)垃圾回收器的大致工作流程

四、垃圾回收算法

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

(2)标记 - 整理算法(Mark Compact)

(3)复制算法

五、堆的不同区域(分代垃圾回收)

六、堆的不同区域使用不同的垃圾回收算法

七、垃圾回收器

1. 有哪些垃圾回收器

2. CMS垃圾回收器和G1垃圾回收器

八、其它一些说明

JVM相关参数


一、JVM内存区域划分

 二、从一个基本问题开始引入垃圾回收

        从一个基本问题思考,既然要进行垃圾回收,那么可定要从某一个区域(内存区域)进行回收(即,把内存区域中的某些对象当成垃圾,把这些垃圾对象占用的内存区域回收回来,从而释放内存,避免这个区域的内存被占满)。

        通过以上一个基本的问题出发,我们可以明确如下几个问题:

(1)在哪个区域上进行垃圾回收(换句话说:JVM的哪个区域可以执行垃圾回收这个动作);

(2)在这个可以执行垃圾回收的区域中,如何识别出哪些对象是垃圾;

(3)确定了哪些对象可以被当成垃圾进行回收,那么应该使用什么算法进行回收;

(4)针对这个可以执行垃圾回收的区域,此区域又可以分为哪些不同的小区域,各个小区域应该使用哪种垃圾回收算法;

        针对以上几个问题,下面逐一进行说明:

三、GC作用的区域

       JVM(Java虚拟机)的垃圾回收主要是针对堆内存进行的。堆内存是用来存储对象实例的地方,而垃圾回收的主要任务就是识别并清除不再被任何活跃对象引用的对象,从而释放它们占用的内存空间。因此,垃圾回收器主要关注的是堆内存中的对象,以确保内存的有效利用和系统性能的提高。

三、如何确定一个对象是否可以被当成垃圾进行回收

        既然已经知道了,垃圾回收是针对堆内存的,那么如何判断堆内存中的哪些对象可以被当成垃圾进行回收呢?有如下几种方法:

(1)引用计数法

        每个对象都会有一个与之关联的引用计数器,用来记录指向该对象的引用数量;当一个对象被引用时,其引用计数加一;当一个对象的引用被释放时,其引用计数减一。当引用计数为0时,表示没有任何引用指向该对象,即可被视为垃圾对象,可以被回收。

        尽管引用计数法简单直观,但也存在一些问题,例如无法处理循环引用的情况(如:当两个或多个对象互相引用导致引用计数不为零)。由于这一缺陷,现代的Java虚拟机一般不再使用引用计数法作为判断对象可以是否被当成垃圾的依据,而是采用基于可达性分析的算法来判断对象是否可以被当成垃圾进行回收。

(2)可达性分析算法

        Java虚拟机中的垃圾回收器采用可达性分析算法来探索所有存活的对象。问题来了,如何进行探索呢?

        是通过扫描堆中的对象,看是否能够沿着 GC Root 对象为起点的引用链找到该对象,找不到,表示可以回收;但是问题又来了,哪些对象可以作为 GC Root对象呢?

        可以使用 Eclipse(没错,就是哪个被IDEA打趴下的Eclipse)提供的一个工具(Memory Analyzer (MAT))进行查看(这个工具需要结合 JDK提供的 jmpa 工具进行使用),MAT分析工具官方下载链接:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

(3)引用的类型

        上面提到了<引用>,在Java中,有如下几种引用类型:

(3.1)强引用(Strong Reference)

        强引用是最常见的引用类型,在代码中使用最频繁。当我们使用new关键字创建一个对象时,默认就是强引用。只要强引用存在,垃圾回收器就不会回收被引用的对象。即使内存不足时,系统也会抛出OutOfMemoryError异常而不是回收强引用对象。

        【只有所有GC Roots 对象都不通过【强引用】引用该对象后,该对象才能被垃圾回收】

(3.2)软引用(Soft Reference)

        软引用是一种相对强引用较弱的引用类型。通过SoftReference类来实现。当内存不足时,Java虚拟机会根据一定的策略来决定是否回收软引用对象。通常情况下,只有在内存不足且没有强引用指向该对象时,才会回收软引用对象。软引用适用于对内存敏感的缓存等场景。

        【仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象】

        【可以配合引用队列来释放软引用自身】

(3.3)弱引用(Weak Reference)

        弱引用(Weak Reference):弱引用是一种比软引用更弱的引用类型。通过WeakReference类来实现。当垃圾回收器进行回收时,无论内存是否充足,只要弱引用对象没有被强引用指向,就会被回收。弱引用常用于实现对象注册表、缓存等场景。

        【仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象】

        【可以配合引用队列来释放弱引用自身】

(3.4)虚引用(Phantom Reference)

        虚引用是最弱的引用类型之一。通过PhantomReference类来实现。虚引用的作用是在对象被回收之前,允许程序员在对象被回收时收到一个系统通知。虚引用无法通过引用访问对象,而是通过ReferenceQueue来获取相关通知。虚引用常与引用队列(ReferenceQueue)一起使用,用于某些特定的清理操作。

        【必须配合引用队列使用,主要配合ByteBuffer使用,被引用对象回收时,会将虚引用入队,由Reference Handler 线程调用虚引用相关方法释放直接内存

(3.5)终结器引用(Final Reference)

        终结器引用是一种比较特殊的引用类型。当对象具有终结器(Finalizer)时,它会被分配给一个终结器引用。终结器引用的主要作用是在对象销毁前,通过执行终结器方法进行资源释放和清理。然而,终结器的使用已不推荐,因为它们具有不确定性和性能问题,应尽量避免使用。

        【无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象】

(4)垃圾回收器的大致工作流程

(1)根搜索:垃圾回收器会从一组称为"GC Roots"的起始点开始遍历,例如虚拟机栈中的引用、静态变量等。任何能从GC Roots开始遍历到的对象都被认为是活跃对象,不会被回收;

(2)可达性分析:从GC Roots出发,遍历堆中的对象图,标记所有被引用的对象为活跃对象;

(3)清除阶段:遍历整个堆,将未被标记为活跃对象的对象标记为垃圾,并进行回收。

        注意:JVM使用了不同的垃圾回收算法,例如标记-清除、标记-整理和复制算法等。这些算法的具体实现细节可能会有所不同,但基本的判断原则都是通过可达性分析来确定对象是否可回收。

        此外,Java还提供了finalize()方法,允许对象在被回收之前执行特定的清理操作。但是,由于finalize()方法的执行时机不确定且开销较大,因此在实际应用中,建议使用显式的资源释放方式,如使用try-with-resources语句块来确保及时释放资源。

四、垃圾回收算法

        既然确定了哪些对象可以被当作垃圾进行回收,那么应该使用怎样的方法进行垃圾回收呢?换句话说,使用什么垃圾回收算法呢?

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

示意图:

标记阶段(Marking Phase)

        从根对象(如全局变量和活跃线程的栈和寄存器)开始,通过遍历对象之间的引用关系,标记所有能够被访问到的对象。在这个阶段,所有被标记的对象被视为活动对象,而未被标记的对象则被视为垃圾对象。 

清除阶段(Sweeping Phase)

        标记阶段之后,系统会对堆中的所有对象进行线性遍历,清除未被标记的对象,并将它们所占用的内存空间进行释放。这样就完成了对垃圾对象的回收工作。

优点:

  • 简单直观,能够有效地回收不再使用的内存对象

缺点:

  • 内存碎片化问题和回收效率问题(由于清除阶段释放了大量的内存空间,留下了不连续的内存碎片,可能会导致内存分配时的碎片化问题)
  • 此外,标记-清除算法在执行过程中会停止整个应用程序(Stop the world, STW),可能会导致较长的停顿时间,影响了应用程序的响应速度。

        因此,在实际应用中,往往会结合其他垃圾回收算法,如压缩算法(Compaction)、分代算法(Generational Collection)等,来解决标记-清除算法存在的问题,以提高内存管理的效率和性能。 

(2)标记 - 整理算法(Mark Compact)

示意图:

标记-整理算法有如下几个阶段:

标记(Mark)

        从根对象出发,遍历整个对象图,标记所有活跃对象。活跃对象是指仍然被引用的对象,而非垃圾对象。

整理(Compact)

        将所有活跃对象向内存的一端移动,紧凑排列,以便在后续步骤中形成连续的可用内存空间。

清除(Sweep)

        从堆的另一端开始,将未被标记的对象视为垃圾,将其回收,并释放相应的内存空间。

更新引用:

        在整理过程中,由于对象的位置发生了变化,需要更新所有对对象的引用,确保引用指向正确的内存地址。

优点:

        标记-整理算法的优点是可以大幅减少内存碎片的产生,提高内存的利用率

缺点:

        它需要进行整理和移动对象的操作,可能会引入较大的停顿时间,影响应用程序的响应性能。因此,该算法通常适用于较小的堆内存或对停顿时间要求较低的场景。

(3)复制算法

示意图:

复制算法有如下几个步骤:

  1. 将内存空间分为两个相等的区域:From区和To区。
  2. 在From区中分配内存并创建对象。
  3. 当From区的内存耗尽时,启动垃圾回收机制。
  4. 从From区中将存活的对象复制到To区。
  5. 清空From区中的所有对象,并交换From区和To区的角色。

        复制算法的优点在于简单高效,它解决了标记-清除算法和标记-整理算法中会产生的内存碎片问题。但是,由于需要将存活对象复制到另一块区域,因此复制算法会导致内存利用率降低一半(需要双倍的内存空间),适用于新生代的内存回收,不适合用于老年代的大规模对象回收。

        因此,在JVM中,通常会将堆内存划分为新生代老年代,新生代主要使用复制算法来进行垃圾回收,而老年代则会采用其他更适合的算法,例如标记-整理算法或标记-清除算法。

五、堆的不同区域(分代垃圾回收)

        分代回收算法是JVM的一种垃圾回收算法,基于对象的生命周期,将堆内存分为不同的代(Generation),并对不同代采用适合的垃圾回收算法。通常将堆内存划分为新生代、老年代和持久代(或元数据区),其中新生代又可以进一步划分为Eden区、Survivor区1和Survivor区2

        分代回收算法的主要思想是:大部分对象的生命周期很短,很快就会被回收,而只有少数对象的生命周期很长,需要在堆内存中存活较长时间。因此,我们可以采用不同的垃圾回收算法来针对不同的对象生命周期,以达到更好的性能和效果。

        在分代回收算法中,新生代通常使用复制算法进行垃圾回收,因为大多数对象的生命周期较短,而老年代则采用标记-整理算法或标记-清除算法,因为老年代中的对象生命周期更长,需要更高效的回收算法。而持久代主要存储类元数据信息等不会被回收的数据,一般不需要进行垃圾回收。

        分代回收算法的优点在于根据对象的生命周期采用不同的回收算法,可以更好地平衡垃圾回收的效率和停顿时间(STW),并减少不必要的内存复制和整理操作。但是,分代回收算法需要更多的内存空间来划分不同的代,而且需要更复杂的垃圾回收机制来管理不同代之间的引用关系,因此在实际应用中需要根据具体情况进行选择和配置。

以下是学习黑马视频-JVM教程截的图

六、堆的不同区域使用不同的垃圾回收算法

        通过《五、堆的不同区域(分代垃圾回收)》可知:

  1. 新生代通常使用复制算法进行垃圾回收,因为大多数对象的生命周期较短;
  2. 老年代则采用标记-整理算法或标记-清除算法,因为老年代中的对象生命周期更长,需要更高效的回收算法。
  3. 持久代主要存储类元数据信息等不会被回收的数据,一般不需要进行垃圾回收。

七、垃圾回收器

Oracle官方文档:Available Collectors (oracle.com)

1. 有哪些垃圾回收器

 

从<楼仔>的公众号截取的图:

 

2. CMS垃圾回收器和G1垃圾回收器

CMS(Concurrent Mark Sweep)垃圾回收器和G1(Garbage-First)垃圾回收器都是Java虚拟机的垃圾回收器,它们在内存管理和垃圾回收策略上有一些区别。

  1. 并发性能:CMS垃圾回收器是一种以最短停顿时间为目标的垃圾回收器。它使用并发标记和并发清理的方式来实现垃圾回收,可以在垃圾回收过程中与应用程序并发执行,减少停顿时间,提高系统的响应能力。而G1垃圾回收器也具有并发标记和并发清理的特性,但相比CMS,G1进一步改进了并发性能,通过将堆内存划分为多个小块(Region),并采用增量式的方式进行垃圾回收,可以更好地控制每次垃圾回收的时间。

  2. 内存模型:CMS垃圾回收器使用的是分代回收的思想,将堆内存划分为年轻代和老年代。年轻代使用复制算法进行垃圾回收,老年代使用标记-清除算法。而G1垃圾回收器则是基于分区(Region)的内存模型,将整个堆内存划分为多个相等大小的区域,并且不再明确区分年轻代和老年代。G1会根据垃圾回收的情况动态地选择进行回收的区域。

  3. 碎片整理:CMS垃圾回收器在进行垃圾回收时,不会对整个堆内存进行整理,因此可能会导致堆内存的碎片化问题。而G1垃圾回收器采用了分区的方式,并在垃圾回收过程中进行了部分的碎片整理,可以较好地避免堆内存的碎片化问题。【注意:G1垃圾回收器(1)同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是 200 ms;(2)超大堆内存,会将堆划分为多个大小相等的 Region;(3)整体上是 标记+整理 算法,两个区域之间是 复制 算法 ;(4)相关JVM参数:< -XX:+UseG1GC >   < -XX:G1HeapRegionSize=size >  < -XX:MaxGCPauseMillis=time >

  4. 停顿时间:CMS垃圾回收器通过并发的方式来减少垃圾回收的停顿时间,但无法完全避免停顿。而G1垃圾回收器则通过控制每次垃圾回收的时间和并发执行的阶段,可以更好地控制全局的垃圾回收时间,并且具有更可预测的停顿时间。

综上所述,CMS垃圾回收器和G1垃圾回收器都是面向低停顿时间的垃圾回收器,但G1相比CMS在并发性能、内存模型、碎片整理和停顿时间上都有进一步的改进和优化。根据具体的应用场景和需求,可以选择适合的垃圾回收器来进行内存管理。

        JDK 1.8默认使用的垃圾回收器是ParallelGC,也称为Parallel Scavenge收集器。这是一种基于标记-复制算法的垃圾回收器,主要针对年轻代进行垃圾回收。ParallelGC使用多个线程并行地进行垃圾回收操作,可以充分利用多核CPU的优势,以提高垃圾回收的效率。

        另外,在JDK 1.8中还引入了G1垃圾回收器,它是一种基于分区(Region)的垃圾回收器,相比于ParallelGC具有更好的并发性能和更可预测的停顿时间。但G1不是默认的垃圾回收器,需要通过特定参数进行配置才能启用。

        需要注意的是,JDK 1.8中的垃圾回收器并不是固定的,可以通过虚拟机参数进行配置。在实际应用中,需要根据具体的场景和需求来选择合适的垃圾回收器。

八、其它一些说明

JVM相关参数

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

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

相关文章

(Matlab)基于CNN-LSTM的多维时序回归预测(卷积神经网络-长短期记忆网络)

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、代码实际运行结果展示&#xff1a; 三、部分代码展示&#xff1a; 四、本文完整代码数据下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码…

【Kubernetes】控制器Statefulset

Statefulset控制器 一、概念二、Statefulset资源清单文件编写技巧2.1、查看定义Statefulset资源需要的字段2.2、查看statefulset.spec字段如何定义2.3、查看statefulset的spec.template字段如何定义 三、Statefulset使用案例&#xff1a;部署web站点3.1、编写一个Statefulset资…

【四】记一次关于架构设计从0到1的讨论

记一次关于架构设计从0到1的讨论 简介&#xff1a; 在一次面试中和面试官讨论起来架构设计这个话题&#xff0c;一聊就不知不觉一个小时了&#xff0c;感觉意犹未尽。现在回想起来感觉挺有意思的&#xff0c;古人说独学而无友则孤陋而寡闻&#xff0c;的确是这样的&#xff0c…

【并发编程篇】读锁readLock()和写锁writeLock()

文章目录 &#x1f6f8;情景引入⭐解决问题 readLock()和writeLock()都是ReadWriteLock接口中定义的方法&#xff0c;用于获取读锁和写锁。 readLock()方法返回一个读锁&#xff0c;允许多个线程同时获取该锁&#xff0c;以进行并发读取操作。如果当前已有一个写锁或其他线程正…

HDFS NFS Gateway(环境配置,超级详细!!)

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f618;《CTF专栏》超级详细的解析&#xff0c;宝宝级教学让你从蹒跚学步到健步如飞&#x1f648; &#x1f60e;《大数据专栏》大数据从0到秃头&#x1f47d;&…

云原生之深入解析基于FunctionGraph在Serverless领域的FinOps的探索和实践

一、背景 Serverless 精确到毫秒级的按用付费模式使得用户不再需要为资源的空闲时间付费。然而&#xff0c;对于给定的某个应用函数&#xff0c;由于影响其计费成本的因素并不唯一&#xff0c;使得用户对函数运行期间的总计费进行精确的事先估计变成了一项困难的工作。以传统云…

免费福利马上截止!深圳的户外小伙伴别错过!COSP2024体育展来了

COSP2024户外博览会 展会时间&#xff1a;2024年3月14-16日 展会地址&#xff1a;深圳福田会展中心 户外运动爱好者不可错过&#xff01; COSP2024户外博览会不仅可以逛展 看各种露营装备、户外器材 还有各种沙龙、峰会活动 就在明年开年&#xff0c;阳春三月天&#xf…

解决 MATLAB 遗传算法中 exitflg=4 的问题

一、优化问题简介 以求解下述优化问题为例&#xff1a; P 1 : min ⁡ p ∑ k 1 K p k s . t . { ∑ k 1 K R k r e q l o g ( 1 α k ∗ p k ) ≤ B b s , ∀ k ∈ K p k ≥ 0 , ∀ k ∈ K \begin{align} {P_1:}&\mathop{\min}_{\bm{p}}{ \sum\limits_{k1}^K p_k } \no…

微信小程序开发学习(上强度):从0开始写项目

前置知识 1、配置插件 微信小程序 基础模板引入sass的两种方法_微信小程序使用sass-CSDN博客 之后在对应页面里新建一个scss文件&#xff0c;写css 2、注册小程序&#xff0c;有个自己的appid&#xff0c;不用测试号了 5.1.注册小程序账号获取appid及个人和企业版差异_哔哩…

MATLAB学习笔记(一)求解三阶微分方程

一、求解三阶微分方程 对于多变量三阶微分方程求解问题&#xff0c;这里介绍一种求解方法。 例题如下&#xff1a; 对于以上方程&#xff0c;给定边界条件&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c;。求解和的表达式。 二、解题步骤 &#xff08;1&…

【扩散模型】7、GLIDE | 文本指引的图像生成和编辑

论文&#xff1a;GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models 代码&#xff1a;https://link.zhihu.com/?targethttps%3A//github.com/openai/glide-text2im 出处&#xff1a;OpenAI 一、背景 在扩散模型经过了一系列…

【论文解读】CNN-Based Fast HEVC Quantization Parameter Mode Decision

时间&#xff1a;2019 年 级别&#xff1a;SCI 机构&#xff1a;南京信息工程大学 摘要 随着多媒体呈现技术、图像采集技术和互联网行业的发展&#xff0c;远程通信的方式已经从以前的书信、音频转变为现在的音频/视频。和 视频在工作、学习和娱乐中的比例不断提高&#xff0…

微服务-springcloud(eureka实践, nacos实践)

Spring 体系图 版本关系 eureka 实践 1 父工程依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.14</version> </parent> <dependencyManage…

SD卡写保护怎么解除?这3个方法很实用!

“我的sd卡用了很久了&#xff0c;一直都可以正常使用的&#xff0c;但是最近不知道为什么&#xff0c;突然就显示sd卡写保护了。我无法存入任何数据&#xff0c;请问有什么方法可以解决该问题吗&#xff1f;” SD卡是一种常见的存储设备&#xff0c;被广泛应用于手机、相机、平…

为什么react call api in cDidMount

为什么react call api in cDM 首先&#xff0c;放到constructor或者cWillMount不是语法错误 参考1 参考2 根据上2个参考&#xff0c;总结为&#xff1a; 1、官网就是这么建议的&#xff1a; 2、17版本后的react 由于fiber的出现导致 cWM 会调用多次&#xff01; cWM 方法已…

05-垃圾收集器ParNewCMS与底层三色标记算法详解

文章目录 垃圾收集算法分代收集理论标记-复制算法标记-清除算法标记-整理算法 垃圾收集器Serial收集器Parallel Scavenge收集器ParNew收集器CMS收集器 CMS的相关核心参数亿级流量电商系统如何优化JVM参数设置(ParNewCMS) 垃圾收集底层算法实现三色标记多标-浮动垃圾漏标-读写屏…

模式识别与机器学习(八):决策树

1.原理 决策树&#xff08;Decision Tree&#xff09;&#xff0c;它是一种以树形数据结构来展示决策规则和分类结果的模型&#xff0c;作为一种归纳学习算法&#xff0c;其重点是将看似无序、杂乱的已知数据&#xff0c;通过某种技术手段将它们转化成可以预测未知数据的树状模…

7.串口通信uart编写思路及自定义协议

前言&#xff1a; 串口是很重要的&#xff0c;有许多模块通信接口就是串口&#xff0c;例如gps模块&#xff0c;蓝牙模块&#xff0c;wifi模块还有一些精度比较高的陀螺仪模块等等&#xff0c;所以学会了串口之后&#xff0c;这些听起来很牛批的模块都能够用起来了。此外&#…

盒子 Box

UVa1587 思路&#xff1a; 1.输入每个面的长宽并将每个面较长的一边放在前面 2.判断是否存在三对面分别相等 3.判断是否存在三组四棱相等 #include <stdio.h> #include <stdlib.h> #define maxn 100int cmp(const void* e1, const void* e2) {return (int)(*(d…

深度神经网络下的风格迁移模型(C#)

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 这个是C#版本的&#xff0c;这里就只放出代码。VB.Net版本请参看 深度神经网络下的风格迁移模型-CSDN博客 斯坦福大学李飞飞团队的…