Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >jvm的垃圾回收算法_jvm垃圾回收策略

jvm的垃圾回收算法_jvm垃圾回收策略

作者头像
全栈程序员站长
发布于 2022-10-01 05:02:09
发布于 2022-10-01 05:02:09
83600
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

前言

相比C语言,JVM虚拟机一个优势体现在对对象的垃圾回收上,JVM有一套完整的垃圾回收算法,可以对程序运行时产生的垃圾对象进行及时的回收,以便释放JVM相应区域的内存空间,确保程序稳定高效的运行,但在真正了解垃圾回收算法之前,有必要对JVM的对象的引用做一个简单的铺垫

JVM对象可达性分析算法

  • Java虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象
  • 扫描堆中的对象,看是否能够沿着GC Root对象为起点的引用链找到该对象,找不到表示可以被回收

想象一下,对象在什么情况下会被认为是垃圾对象呢?

  • 当一个对象没有被任何引用了,就认为对象无用了(如图一)
  • 当一组对象没有被任何引用了,可以认为这组对象无用了(如图二)

下面通过一段简单的程序代码,在不同的时刻导出dump日志,利用MAT分析工具来说明下这个问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) throws Exception{
        List<Object> list1 = new ArrayList<>();
        list1.add("aaa");
        list1.add("bbb");
        System.out.println(1);
        System.in.read();

        list1 = null;
        System.out.println(1);
        System.in.read();
        System.out.println("end");

    }

运行程序,利用下面的命令导出两个时刻的dump文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
map -dump:format=b,live,file=a.dump 17356

分析第一个文件,在第一个时刻,此时由于list1集合中放了2个元素,因此该对象存在引用关系

再分析第二个文件,在第二个时刻,此时由于list1置为null,因此该对象没有被引用的地方了,在gc root中找不到list1对象了

通过上面简单的案例演示和说明,我们再次明确,对象被标为垃圾的前提是该对象从GC Root出发进行搜索时,找不到对该对象的引用,即为不可达对象

几种常用的垃圾回收算法

1、引用计数法

引用计数法在JVM的早期版本中有用到,引用计数是指采用计数器说明引用对象的个数,即为某个对象设置一个引用对象数量的计数器,如果该对象被引用了,计数器的数量加1,否则减一,当计数器的数值为0的时候,垃圾回收器将该对象进行回收

如下图所示,某一时刻,对象A,B,C各自持有对对象P的引用,到另一时刻A,B,C不再对P对象进行引用了,计数器的值归为0,此时垃圾回收器就对P对象进行垃圾回收

引用计数法在JVM垃圾回收算法中逐渐被废弃,很简单,如果存在对象之间的循环引用,则计数器的count值永远不会清0,如此对象将会一直存在内存中得不到释放

2、根搜索算法

根搜索算法是JVM的默认垃圾回收算法,也叫做“可达性分析算法”,即从GCRoot出发,有引用的对象都是不可回收的,其他的可以进行标记后再回收

如下图所示,对某个线程栈来说,里面有局部变量,有静态变量,常量池,或对本地native方法的调用,假设从某个栈帧的局部变量出发,可认为是GCRoot的搜索起点,以此为起点,搜索整个引用链条上的所有引用对象,在这个链条上的对象认为是GCRoot可达的对象,否则将会被设为可回收对象被垃圾回收器回收

3、标记清除法(Mark-Sweep)

标记清除算法主要经历标记和清除2个步骤,通过根搜索算法中的可达性分析之后,那些被标记为垃圾对象的内存空间,通过该算法直接清除

标记清除算法简单粗暴,效率很高,因为不涉及到其他的步骤,但是从下面的图示也可以看到,标记清除算法产生了不连续的内存碎片(产生了内存间隙)导致其内存使用率比较低,如果程序中需要为某个大对象分配一大块连续的内存空间,则很难通过这种算法腾出这样的内存空间,因此该算法在JVM中并没有使用到(作为一种垃圾回收算法的思想值得借鉴)

4、复制交换算法(Mark-Sweep)

为解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当某一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题

在堆的年轻代进行GC的时候使用的就是复制算法,还记得新生代的区域划分吗?S0和S1两个区域的内存在实际使用时,总是其中一块在使用,当达到了minor gc的条件时,就按照复制算法,将这块空间中存活的对象转移到另一块,再清理当前这块空间的垃圾对象

总结来说,复制算法速度快,无内存碎片,但缺点也比较明显,就是浪费空间,在年轻代的 Minor Gc中使用

5、标记压缩算法(Mark-Compact)

为解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存

标记压缩算法整个垃圾回收的过程包括,标记 -> 压缩 -> 整理 ->清除,通过下图展示也不难发现,标记压缩进行垃圾回收之后,整个内存区域的分布比较连续(无内存碎片),但是很明显这种算法的中间操作步骤相对上面两种算法要复杂,因此在进行GC过程中比较耗时效率较低,在老年代的Full Gc时使用的就是标记压缩算法

JVM 分代收集算法

在JVM的内存结构中,按照堆内存的结构划分,大的方面可以分为年轻代和老年代,堆内存是JVM中进行垃圾回收的主要区域

但是各个区域在使用过程中的作用,对象生成规则,对象生命周期的不同又可以细分为各个逻辑上的结构,比如在新生代区域,可以划分为 Eden区和Survivor区,而Survivor再细分为from(s0)区和to(s1)区,通过区域的划分,各个区域的职责更加明确

我们知道,新生代和老年代一个很大的区别在于,新生代是对象频繁产生的区域,也是Minor Gc很频繁的区域,而老年代中的对象大多则是比较稳定的对象,从这个角度上说,各个区域在进行垃圾回收时策略自然不相同

分代收集算法是目前大部分JVM的垃圾收集器采用的算法,新生代对象朝生夕死,生命周期短,内存空间需要频繁的进行清理以应对快速而来的新对象,因此需要更高效的垃圾回收算法

新生代

目前大部分垃圾收集器对新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间(一般为8:1:1),每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间

老年代

老年代内存空间相对较大,可以存放更多的对象,通常情况下每次发生Full Gc的间隔时间也较长,而且在老年代中经常需要存放一些大对象,需要连续的内存空间,基于这些特点,在目前主流的JVM垃圾回收器中对于老年代采用压缩算法

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月11日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JVM 垃圾回收算法
在标记阶段首先通过根节点(GC Roots),标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。
一个会写诗的程序员
2020/05/18
1.1K2
JVM 垃圾回收算法
JVM垃圾回收算法
分为标记和清除两个阶段,首先标记出所有需要回收的对象,标记完成后统一回收所有被标记的对象
终有链响
2024/07/29
1480
JVM垃圾回收算法
JVM垃圾回收算法以及垃圾回收器机制
JVM中,程序计数器、虚拟机栈、本地方法栈都是都是线程私有的,随线程而生随线程而灭,栈帧(栈中的对象)随着方法的进入和退出做入栈和出栈操作,实现了自动的内存清理。
Java技术债务
2022/08/09
6610
JVM垃圾回收算法以及垃圾回收器机制
JVM垃圾回收算法
判断Java中对象存活的算法 1.引用计数器算法: 引用计数器算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器+1,当引用失效的时候,计数器-1,当计数器为0的时候,JVM就认为对象不再被使用,是“垃圾”了。 引用计数器实现简单,效率高;但是不能解决循环引用问问题(A对象引用B对象,B对象又引用A对象,但是A,B对象已不被任何其他对象引用),同时每次计数器的增加和减少都带来了很多额外的开销,所以在JDK1.1之后,这个算法已经不再使用了。 2.根搜索方法: 根搜索方法是通过一些“GCRo
java404
2018/05/18
7040
垃圾回收算法与 JVM 垃圾回收器综述
我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的回收方法。不同回收器的实现细节各有不同,但总的来说基本所有的回收器都会关注如下两个方面:找出所有的存活对象以及清理掉所有的其它对象——也就是那些被认为是废弃或无用的对象。Java 虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商、不同版本的虚拟机所提供的垃圾收集器都可能会有很大差别,并且一般都会提供参数供用户根据自己的应用特点和要求组合出各个年代所使用的收集器。其中最主流的四个垃圾回收器分别是:通常用于单 CPU 环境的 Seri
Java高级架构
2018/04/19
8550
垃圾回收算法与 JVM 垃圾回收器综述
jvm垃圾回收详解_java 垃圾回收器
JVM 会自动帮程序员进行垃圾回收,并不需要程序员手动的进行垃圾回收(C++等语言需要自己手动回收垃圾),了解 JVM 的垃圾回收,可以帮程序员写出占用内存更小、更高效的程序。
全栈程序员站长
2022/10/01
1.2K0
jvm垃圾回收详解_java 垃圾回收器
关于java的垃圾回收机制,下面哪些结论_java垃圾回收算法有哪些
基于以上两点,收集器应该将Java堆划分出不同的区域,然后将回收对象依据年龄等分配到不同的区域中存储。但是可能会有跨代引用,于是就有了
全栈程序员站长
2022/09/27
4240
JVM内存分配策略,及垃圾回收算法
说起垃圾收集(Garbage Collection, GC),想必大家都不陌生,它是JVM实现里非常重要的一环,JVM成熟的内存动态分配与回收技术使Java(当然还有其他运行在JVM上的语言,如Scala等)程序员在提升开发效率上获得了惊人的便利。理解GC,对于理解JVM和Java语言有着非常重要的作用。并且当我们需要排查各种内存溢出、内存泄漏问题时,当垃圾收集称为系统达到更高并发量的瓶颈时,只有深入理解GC和内存分配,才能对这些“自动化”的技术实施必要的监控和调节。
李红
2019/09/17
1.2K0
JVM内存分配策略,及垃圾回收算法
JVM学习记录-垃圾回收算法
简述 因为各个平台的虚拟机的垃圾收集器的实现各有不同,所以只介绍几个常见的垃圾收集算法。 JVM中常见的垃圾收集算法有以下四种: 标记-清除算法(Mark-Sweep)。 复制算法(Copying)。 标记整理算法(Mark-Compact)。 分代收集算法(Generational Collecting)。  标记-清除算法 标记-清除算法是现代垃圾回收算法的思想基础,主要分为两个阶段:标记阶段和清除阶段。首先根据可达分析算法,标记处可以回收的对象,标记完成后,进行清除阶段,将标记为可回收的对象进行清除。
纪莫
2018/06/14
5860
JVM的垃圾回收算法
JVM的垃圾回收算法 一,如何判断对象已经消亡 1,引用计数算法 一个对象如果没有任何引用指向它,就可认为该对象已经”消亡“,这种方法有个缺点就是无法检测到引用环的存在。 算法特点 1. 需要单独的字段存储计数器,增加了存储空间的开销; 2. 每次赋值都需要更新计数器,增加了时间开销; 3. 垃圾对象便于辨识,只要计数器为0,就可作为垃圾回收; 4. 及时回收垃圾,没有延迟性; 5. 不能解决循环引用的问题; 2,根搜索算法 Java使用根搜索算法回收垃圾,该算法的基本原理:定义一系列名为GC Roots的
Spark学习技巧
2018/01/30
6570
JVM的垃圾回收算法
深入理解JVM - 垃圾回收算法
这一期讲述垃圾回收的算法。我们根据分代的理念讲述一下JVM是使用什么算法对于不同分代的对象进行垃圾回收的的,同样内容十分基础,但是对于学习JVM后续的内容十分重要。
阿东
2021/08/16
1.9K0
深入理解JVM - 垃圾回收算法
看一看JVM垃圾回收算法
Java有着自己一套的内存管理机制,不需要开发者去手动释放内存,开发者只需要写好代码即可,运行过程中产生的垃圾都由JVM回收。那JVM都是用哪些算法进行垃圾回收呢?
索码理
2022/12/28
3090
看一看JVM垃圾回收算法
一张图看懂JVM之垃圾回收算法详解
导读 在之前的内容中,我们通过一张图的方式(图?),从总体上对JVM的结构特别是内存结构有了比较清晰的认识,虽然在JDK1.8+的版本中,JVM内存管理结构有了一定的优化调整。主要是方法区(持久代)
用户5927304
2019/07/31
4860
简述 JVM 垃圾回收算法
之前我们学习了 JVM 基本介绍 以及 什么样的对象需要被 GC ?,今天就来学习一下 JVM 在判断出一个对象需要被 GC 会采用何种方式进行 GC。在学习 JVM 如何进行垃圾回收方法时,发现所谓的 JVM 垃圾回收思想和现实生活的场景有很多相似的地方。所以本文用餐厅回收餐桌的方式类比 JVM 垃圾回收算法,应该能帮助 JVM 学习的理解和记忆。
周三不加班
2019/06/04
3970
简述 JVM 垃圾回收算法
JVM的垃圾回收
垃圾回收机制是java的一个特性,相较于c/c++程序员需要自己分配内存,在使用结束后自己回收内存而言,Java实在对程序员太友好了(所以头发较多点)。Java的垃圾回收全部都是由虚拟机自动完成的,不需要程序员额外写啥代码。作为一个Java程序猿,学习GC是非常有必要的,根据项目特性,优化GC也是一个优秀程序猿的基本能力之一。
用户3467126
2019/08/23
4960
JVM的垃圾回收
Java的垃圾回收和内存分配策略
在介绍Java的垃圾回收方法之前,我们先来了解一下Java虚拟机在执行Java程序的过程中把它管理的内存划分为若干个不同的的数据区的什么?
stringwu
2022/08/12
5050
Java的垃圾回收和内存分配策略
JVM 垃圾回收详解
内存泄漏:又叫“存储泄漏”,对象不会在被程序使用了,但是GC又不能回收他们。例如:IO流不适用了但是没有被close、数据库连接JDBC没有被close。这些对象不会被回收就会占据内存,大量的此类对象存在,也是导致内存溢出的原因。
程序员子龙
2023/12/18
2950
JVM垃圾回收机制
对于大多数应用来说,Java 堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块。Java 堆是被所有线程共享的一块 内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java 堆是垃圾收集器管理的主要区域,因此很多时候也被称做“GC 堆”。堆的大小可以通过参数 –Xms、-Xmx 来指定。
羽毛球初学者
2024/10/12
2010
【原创】JVM 的垃圾回收与算法
每个对象有一个引用计数器,当对象被引用一次则计数器加 1,当对象引用失效一次则计数器减 1,对于计数器为 0 的对象意味着是垃圾对象,可以被 GC 回收。
良月柒
2020/04/14
4030
【原创】JVM 的垃圾回收与算法
深入浅出JVM(十二)之垃圾回收算法
这里推荐一篇有关Spring Boot自动装配的文章:一文彻底弄懂 Spring Boot 自动装配的过程!深入探索与案例解析 文章以@SpringBootApplication注解作为入口,分析其自动装配的核心原理、优缺点,以及扩展根据条件加载,并总结使用案例
菜菜的后端私房菜
2024/11/21
1470
相关推荐
JVM 垃圾回收算法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验