【JAVA】JAVA的垃圾回收机制详解

news2024/11/26 11:43:52

对于Java的垃圾回收机制,它是Java虚拟机(JVM)提供的一种自动内存管理机制,主要负责回收不再使用的对象以释放内存空间。垃圾回收机制主要包括以下几个方面的内容:

  • 垃圾对象的识别:Java虚拟机通过一些算法(如引用计数法、可达性分析法等)来识别不再使用的对象,这些对象被认为是垃圾对象。
  • 垃圾回收算法:Java虚拟机使用不同的垃圾回收算法来回收内存,常见的有标记-清除算法、复制算法、标记-整理算法等。
  • 垃圾回收器:Java虚拟机中有多种不同的垃圾回收器,如Serial收集器、Parallel收集器、CMS收集器、G1收集器等,它们各自具有不同的特点和适用场景。
  • 内存回收时机:垃圾回收器会在一定条件下触发内存回收,比如当堆内存达到一定阈值、程序执行完毕时、调用System.gc()方法时等。

需要注意的是,全局变量的生命周期与整个应用程序的生命周期相同,因此如果全局变量引用的对象一直存在于内存中而不被释放,可能会造成内存泄漏。因此,在使用全局变量时要合理管理其生命周期,确保不再需要时及时释放,以减少内存占用和提高系统性能。

【JAVA】JAVA的垃圾回收机制

    • 一、垃圾对象的识别
      • 1.1、引用计数法
        • 1.1.1、原理:
        • 1.1.2、示例:
      • 1.2、可达性分析法
      • 1.2.1、原理:
      • 1.2.2、示例:
    • 二、垃圾回收算法
      • 2.1、Java的垃圾回收算法主要包括以下几种:
      • 2.2、常用:标记-清除算法之三色标记
        • 2.2.1、原理:
        • 2.2.2、具体的工作流程如下:
    • 三、垃圾回收器
    • 四、内存回收时机

一、垃圾对象的识别

Java对垃圾对象的识别是通过垃圾回收器(Garbage Collector)实现的。垃圾回收器主要依靠两种机制来识别垃圾对象:引用计数法和可达性分析法。下面我会详细介绍这两种机制的原理,并举例说明。

1.1、引用计数法

引用计数法是一种简单的垃圾回收算法,它基于对象的引用计数来判断对象是否是垃圾对象。每个对象都会有一个引用计数器,当有引用指向对象时,引用计数加一;当引用失效或对象被释放时,引用计数减一。当对象的引用计数为零时,表示对象不再被引用,可以被回收。

注意:引用计数法在Java中并不常用,因为它无法解决循环引用的问题,容易造成内存泄漏。两个对象互相引用,这样每一个对象的引用都是1,构成了循环引用,但是并不能被其他对象访问,这两个对象再无任何引用,引用计数算法也就无法回收它们。

1.1.1、原理:

当程序中的某个对象没有任何引用指向它时,它的引用计数会变为零。
垃圾回收器会定期扫描内存中的对象,检查它们的引用计数
引用计数为零的对象被判定为垃圾对象,可以进行回收。

1.1.2、示例:
class MyClass {
    public static void main(String[] args) {
        MyClass obj1 = new MyClass();
        MyClass obj2 = new MyClass();
        
        // obj1和obj2分别引用两个对象
        obj1 = null; // obj1失去对第一个对象的引用,引用计数为1
        System.gc(); // 手动触发垃圾回收
    }
}

1.2、可达性分析法

可达性分析法是Java常用的垃圾回收算法,它基于对象的可达性来判断对象是否是垃圾对象。该算法从一组称为"根"的起始对象开始,通过对象之间的引用链追踪,能够到达的对象称为“可达对象”,不能到达的对象即为“垃圾对象”。

1.2.1、原理:

垃圾回收器从一组根对象开始,例如静态变量、局部变量、常量池等。
通过对象之间的引用关系,追踪可达对象,构成可达图(Reachability Graph)。
无法通过引用链到达的对象被判定为垃圾对象,可以进行回收。

1.2.2、示例:

class MyClass {
    public static MyClass obj; // 静态变量作为根对象
    
    public static void main(String[] args) {
        MyClass obj1 = new MyClass();
        MyClass obj2 = new MyClass();
        
        obj1.obj = obj2; // obj1引用obj2
        obj2.obj = obj1; // obj2引用obj1
        
        obj1 = null; // obj1失去引用,但obj2还可达
        obj2 = null; // obj2也失去引用,整个链断裂
        
        System.gc(); // 手动触发垃圾回收
    }
}

在这个示例中,obj1和obj2通过相互引用形成了一个循环引用,但由于它们都已经失去了外部引用,整个循环链都是不可达的,因此可以被判定为垃圾对象。

总的来说,Java的垃圾回收机制通过引用计数法和可达性分析法来识别垃圾对象,保证了内存的自动管理和释放。在实际编程中,多数情况下采用的是可达性分析法,因为它能够处理循环引用等复杂情况,并且不容易出现误判。

二、垃圾回收算法

2.1、Java的垃圾回收算法主要包括以下几种:

  • 标记-清除算法(Mark and Sweep):这是最基本的垃圾回收算法之一。它分为两个阶段:标记阶段和清除阶段。标记阶段遍历所有可达对象,并标记为活动对象;清除阶段则将未标记的对象进行清除。该算法的缺点是会产生内存碎片,影响内存的连续分配。

  • 标记-整理算法(Mark and Compact):这个算法结合了标记-清除算法和复制算法的优点。它首先标记出所有活动对象,然后将它们向一端移动,然后清除掉端部之外的内存空间。这种方式既避免了内存碎片,又不需要额外的内存空间进行复制。

  • 增量式算法(Incremental):这种算法将垃圾回收过程分为多个阶段,在每个阶段中分别完成标记、清除等操作。这样可以将整个垃圾回收过程分摊到多个时间段,减少了单次垃圾回收的停顿时间。

  • 分代算法(Generational):这种算法根据对象的生命周期将内存分为多个代(Generation),通常分为年轻代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)。新创建的对象会被分配到年轻代,经过几次垃圾回收后仍然存活的对象会被提升到老年代。这样可以根据对象的特点采用不同的垃圾回收策略,提高垃圾回收效率

  • 复制算法(Copying):这个算法将内存分为两个区域:活动区和闲置区。当活动区满了后,将活动区中的存活对象复制到闲置区,然后清空活动区。这种方式避免了内存碎片的问题,但是需要额外的内存空间来进行复制。

2.2、常用:标记-清除算法之三色标记

三色标记算法是一种用于垃圾回收的标记-清除算法。它基于分为三种颜色的标记来管理对象的存活状态,这些颜色通常表示对象的可达性:

2.2.1、原理:
  • 白色:表示对象未被访问,即尚未进行标记。
  • 灰色:表示对象已经被访问,但其引用的对象尚未遍历访问。
  • 黑色:表示对象已经被访问,且其引用的对象已经遍历访问过。

三色标记算法主要用于并发垃圾回收器,如CMS GC(并发标记清除垃圾回收器)和G1 GC(G1垃圾回收器)。它通过在垃圾回收过程中对对象进行颜色标记,以确定对象的可达性和存活状态,从而进行垃圾回收操作。

2.2.2、具体的工作流程如下:
  • 初始标记阶段(Initial Marking):在这个阶段,垃圾回收器首先会标记出根对象和直接与根对象相连的对象,将它们标记为灰色。
  • 并发标记阶段(Concurrent Marking):在初始标记阶段之后,垃圾回收器会启动并发标记阶段,同时与应用程序线程并发执行。在这个阶段,垃圾回收器会遍历访问灰色对象引用的对象,并将它们标记为灰色。被标记过的对象则变为黑色。
  • 重新标记阶段(Remark):在并发标记阶段完成后,可能会有一些新产生的对象被引用,或者有一些灰色对象引用的对象发生了变化。因此,需要进行重新标记阶段,遍历访问这些对象,将其标记为灰色或黑色。
  • 重复上面过程直到没有灰色
  • 并发清除阶段(Concurrent Sweep):最后是并发清除阶段,垃圾回收器会并发执行清除操作,将未被标记为黑色的对象清除,并回收它们所占用的内存空间。

三色标记算法通过不同颜色的标记来实现并发的垃圾回收过程,尽可能地减少了垃圾回收的停顿时间,提高了系统的响应性能。
在这里插入图片描述

在实际应用中,Java的垃圾回收器通常会根据不同的场景和应用程序特点选择合适的垃圾回收算法。例如,年轻代通常采用复制算法,老年代采用标记-清除或标记-整理算法。 Java的垃圾回收器包括串行垃圾回收器(Serial GC)、并行垃圾回收器(Parallel GC)、并发标记清除垃圾回收器(CMS GC)、G1垃圾回收器等,它们各自采用不同的垃圾回收算法和策略。

三、垃圾回收器

  1. Serial GC(串行垃圾回收器):Serial GC是最基本的垃圾回收器,在启动Java应用时可以通过设置JVM参数来指定使用Serial GC。示例命令如下:

    java -XX:+UseSerialGC YourMainClass
    

    这条命令将Java应用使用Serial GC进行垃圾回收。Serial GC适合用于单核CPU和小型应用场景。

  2. Parallel GC(并行垃圾回收器):Parallel GC可以通过设置JVM参数来启用。示例命令如下:

    java -XX:+UseParallelGC YourMainClass
    

    这条命令将Java应用使用Parallel GC进行垃圾回收。Parallel GC适合用于多核CPU和对系统资源要求较高的应用场景。

  3. CMS GC(并发标记清除垃圾回收器):CMS GC也可以通过设置JVM参数来启用。示例命令如下:

    java -XX:+UseConcMarkSweepGC YourMainClass
    

    这条命令将Java应用使用CMS GC进行垃圾回收。CMS GC适用于对响应时间要求较高的应用场景。

  4. G1 GC(G1垃圾回收器):G1 GC同样可以通过设置JVM参数来启用。示例命令如下:

    java -XX:+UseG1GC YourMainClass
    

    这条命令将Java应用使用G1 GC进行垃圾回收。G1 GC适用于大型、内存密集型应用场景。

  5. ZGC(低延迟垃圾回收器):ZGC需要在支持的平台上使用,可以通过设置JVM参数来启用。示例命令如下:

    java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC YourMainClass
    

    这条命令将Java应用使用ZGC进行垃圾回收。ZGC适用于对停顿时间要求极低的应用场景。

  6. Shenandoah GC(低停顿时间垃圾回收器):Shenandoah
    GC同样需要在支持的平台上使用,可以通过设置JVM参数来启用。示例命令如下:

    java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC YourMainClass
    

    这条命令将Java应用使用Shenandoah GC进行垃圾回收。Shenandoah GC适用于对停顿时间要求极低的应用场景。

四、内存回收时机

在JVM里,将堆区划分为两个区域,新生代和老年代,分别用来存放新生成的对象和长期存在的对 象。于是也有了分别针对这两个区域的GC。而这两个区域的GC又是分层的,在新生代的GC后内存仍然不够才有可能触发老年代的GC。

Java中的内存回收时机通常由垃圾回收器(Garbage Collector,GC)来决定,而不是由程序员手动控制。GC会在以下情况下触发内存回收:

  1. 内存空间不足:当Java虚拟机检测到堆内存空间不足时,会触发垃圾回收。这种情况通常包括两种情形:

    • 堆空间不足:指的是新对象无法分配到足够的内存空间。

    • 老年代空间不足:指的是老年代对象无法得到足够的空间来存放。

      老年代的GC,又称为FullGC。分场景来说,FullGC在这些情况下会被触发:

      • 发生Young GC之前进行检查,如果“老年代可用的连续内存空间” < “新生代历次Young GC后升入老年代的对象总和的平均大小”,说明本次Young GC后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,此时会触发FullGC
      • 当老年代没有足够空间存放对象时,会触发一次FullGC

      Eden区域刚开始的设置并没有到达Xmx的最大,会有一个初始值,不够用的时候先扩展一些可扩充空间,仍然不够的时候也会触发young gc。在这里插入图片描述
      在这里插入图片描述
      触发老年代的回收
      在这里插入图片描述

  2. 程序显式调用System.gc():虽然程序员可以调用System.gc()方法请求垃圾回收,但Java虚拟机并不保证会立即执行垃圾回收操作,而是由虚拟机自行决定是否进行回收。

  3. 永久代空间不足(Java 8及之前版本):在Java 8及之前的版本中,永久代(PermGen)用于存放类的元数据等信息。当永久代空间不足时,也会触发垃圾回收。

  4. 对象生命周期结束:当对象不再被引用或者引用被置为null时,它就成为了不可达对象(Unreachable Objects),这些对象会被垃圾回收器识别并回收。

  5. 垃圾回收器的策略:不同的垃圾回收器具有不同的触发条件和策略,比如CMS GC会根据内存的使用情况和回收频率来触发回收,G1 GC则会根据堆空间的利用率和各个分区的情况来决定回收时机。

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

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

相关文章

MySQL索引优化(超详细)篇章2--索引调优

目录 1.索引失效状况2.性能分析3.表的索引信息--调整索引顺序4.删除冗余索引5.最佳左前缀法则5.1下面是一个实际的例子来说明这个概念&#xff1a; 6.数据长度和索引长度占用空间比较 1.索引失效状况 MySQL索引失效通常指的是查询语句无法有效地利用索引&#xff0c;而导致全表…

matlab打开文件对话框

在使用matlab GUI制作时&#xff0c;为了便于用户交互使用&#xff0c;经常设置文件打开对话框&#xff0c;让用户根据实际需要选择打开的文件。下面以打开一张图片为例&#xff0c;matlab代码如下&#xff1a; [temp_filepath,temp_filename]uigetfile(*.jpg,请选择要打开的图…

设计模式(2)创造型设计模式

创建型模式 创建型模式1.工厂模式1.1 抽象工厂模式&#xff08;Abstract factory&#xff09;1.2 工厂方法模式&#xff08;Factory Method&#xff09;1.3 简单工厂模式&#xff08;Simple Factory&#xff09; 2. 建造者模式&#xff08;Builder&#xff09;3. 原型模式&…

【Spring Boot 源码学习】深入 ApplicationArguments 接口及其默认实现

《Spring Boot 源码学习系列》 深入 ApplicationArguments 接口及其默认实现 一、引言二、主要内容2.1 ApplicationArguments2.2 DefaultApplicationArguments2.2.1 成员变量2.2.2 构造方法2.2.3 成员方法 2.3 SimpleCommandLinePropertySource2.4 应用场景2.4.1 准备和配置应用…

基于FPGA的音视频监视器,音视频接口采集器的应用

① 支持1路HDMI1路SDI 输入 ② 支持1路HDMI输出 ③ 支持1080P高清屏显示实时画面以 及叠加的分析结果 ④ 支持同时查看波形图&#xff08;亮度/RGB&#xff09;、 直方图、矢量图 ⑤ 支持峰值对焦、斑马纹、伪彩色、 单色、安全框遮幅标记 ⑥ 支持任意缩放画面&#xff0c;支…

【Java EE】数据库连接池详解

文章目录 &#x1f38d;数据库连接池&#x1f338;Hikari&#x1f338;Druid &#x1f340;MySQL开发企业规范⭕总结 &#x1f38d;数据库连接池 在上⾯Mybatis的讲解中,我们使⽤了数据库连接池技术,避免频繁的创建连接,销毁连接 下⾯我们来了解下数据库连接池 数据库连接池负…

如何利用代理IP进行SEO优化?

“SEO”这个词相信对于做在线业务的朋友来说一定不陌生。 在网络营销中&#xff0c;SEO是至关重要的一环&#xff0c;对于增加有机流量、提升品牌知名度、增加网站的信任度和权威性非常有效。而代理IP在SEO优化中有着不可或缺的作用&#xff0c;它可以帮助网站管理员和SEO专家…

[muduo网络库]——muduo库的Reactor模型(剖析muduo网络库核心部分、设计思想)

一、前言 在学习 C 服务端的过程中&#xff0c;必不可少的一项就是熟悉一个网络库&#xff0c;包括网络库的应用和其底层实现。我们熟知的网络库有 libevent、libev、muduo、Netty 等&#xff0c;其中 muduo 是由陈硕大佬个人开发的 TCP 网络库&#xff0c;最近跟着课程正在深…

回炉重造java----单列集合

体系结构: 集合主要分为两种&#xff0c;单列集合collection和双列集合Map&#xff0c;区别在于单列集合一次插入一条数据&#xff0c;而双列的一次插入类似于key-value的形式 单列集合collection 注:红色的表示是接口&#xff0c;蓝色的是实现类 ①操作功能: 增加: add()&am…

上亿用户面临风险!小米、WPS等知名安卓应用竟藏有“文件覆盖”漏洞

Google Play商店中的几款热门安卓应用程序容易受到与路径遍历相关的漏洞攻击&#xff0c;该漏洞的代号为“Dirty Stream”攻击&#xff0c;恶意应用程序可能会利用此漏洞覆盖易受攻击的应用程序主目录中的任意文件。 微软威胁情报团队的Dimitrios Valsamaras在周三发布的一份报…

【最新点云数据增强综述】深度学习点云数据增强技术的进展

深度学习(DL)已成为点云分析任务(如检测、分割和分类)的主流和有效方法之一。为了减少深度学习模型训练过程中的过拟合,提高模型性能,尤其是在训练数据的数量和/或多样性有限的情况下,增强往往至关重要。虽然各种点云数据增强方法已被广泛应用于不同的点云处理任务中,但…

9.为什么有时候会“烫烫烫”——之函数栈桢

目录 1. 什么是函数栈帧 2. 理解函数栈帧能解决什么问题呢&#xff1f; 3. 函数栈帧的创建和销毁解析 3.1 什么是栈&#xff1f; 3.2 认识相关寄存器和汇编指令 3.3 解析函数栈帧的创建和销毁 小知识&#xff1a;烫烫烫~ Q&A 1. 什么是函数栈帧 我们在写C语言代码…

2024 年 数维杯(A题)大学生数学建模挑战赛 | 多源机会信号建模| 数学建模完整代码+建模过程全解全析

2024数维杯数学建模A题B题C题思路模型代码&#xff08;开赛后第一时间更新&#xff09;及时留意关注哦 https://mbd.pub/o/bread/ZpWakpdq https://mbd.pub/o/bread/ZpWakpdq 2024数维杯数学建模A题B题C题思路模型代码&#xff08;开赛后第一时间更新&#xff09;及时留意关注…

leetcode63.跳跃游戏2(动态规划)

问题描述&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物…

vue项目中使用websocke即时通讯实现系统公告实时获取并提醒

一、使用场景 发布者设置需要发布的公告内容、公告接收用户和发布时间&#xff0c;到达发布时间时及时通知提醒已登录系统用户&#xff0c;使用websocke来实现前端与服务器保持长连接&#xff0c;以便实时过去公告信息。 WebSocket是一种在单个TCP连接上进行全双工通信的协议…

17.Blender RC大佬EEVEE皮肤节点预设导入

如何添加节点预设 在底下的左下角打开Geometry Node Editor 选中正方体&#xff0c;点击新建 当鼠标指针在两个模块之间&#xff0c;是十字的样子时 可以拖出一个新的板块 然后打开文件浏览器 找到节点预设然后拖入到底下的节点编辑界面就可以了或者是blend文件&#xf…

微信小程序流量主如何自定义广告组件后台控制广告显示方式附源码[收藏]

最近开发了一个微信小程序&#xff0c;开通了流量主&#xff0c;引用广告显示。本教程干货满满&#xff0c;附上代码&#xff0c;建议**【收藏点赞】** 微信小程序广告有以下几种&#xff1a;Banner广告、激励广告、插屏广告、视频广告、视频贴片广告、封面广告。 为了增加广告…

pycharm如何对for循环中第n次循序执行断点

目录 在 PyCharm 中&#xff0c;您可以设置条件断点来实现这个功能&#xff0c;这样只有在满足特定条件时断点才会被触发。以下是设置仅在 for 循环的第 n 次迭代时触发断点的步骤&#xff1a; 设置断点&#xff1a; 首先&#xff0c;找到您想要在 for 循环中设置断点的行。点击…

找最大数字-第12届蓝桥杯国赛Python真题解析

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第60讲。 找最大数字&#…

【C++】C/C++中新const用法:const成员

欢迎来到CILMY23的博客 本篇主题为&#xff1a; C/C中新const用法&#xff1a;const成员 个人主页&#xff1a;CILMY23-CSDN博客 系列专栏&#xff1a;Python | C | C语言 | 数据结构与算法 | 贪心算法 | Linux 感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞…