垃圾回收机制

自动垃圾收集

自动垃圾收集是查看堆内存,识别正在使用哪些对象及哪些对象未被删除以及删除未使用对象的过程。

使用中的对象或引用的对象意味着程序的某些部分仍然维护指向该对象的指针。
程序的任何部分都不再引用未使用的对象或未引用的对象,因此可以回收未引用对象使用的内存。
在这里插入图片描述
垃圾回收需要确认3点:

  1. 哪些对象需要被回收
  2. 什么时间被回收
  3. 怎么被回收

如何确定内存需要被回收

该过程的第一步被称为标记。这是垃圾收集器识别哪些内存正在使用而哪些不再使用的地方。
在这里插入图片描述

不同类型内存的判断方法

在这里插入图片描述

  1. 引用计数无法解决循环引用的问题
  2. 在这里插入图片描述
    引用类型和可达性级别
    引用类型
    1.强引用(StrongReference):最常见的普通对象引用,只要还有一个强引用指向一个对象,就不会被回收
    例:Object A=new Object();
    2.软引用(SoftReference):JVM认为内存不足时,才会去试图回收软引用指向的对象。(经常用在缓存场景)
    3.弱引用(WeakReference):虽然是引用,但随时可能被回收掉。
    4.虚引用(PhantomReference):不能通过它访问对象。供了对象被finalize以后,执行指定逻辑的机制(Cleaner)
    可达性级别
    1.强可达(Strongly Reachable):一个对象可以有一个或多个线程可以不通过各种引用访问到的情况。
    2.软可达(Softly Reachable):就是当我们只能通过软引用才能访问到对象的状态。
    3.弱可达(Weakly Reachable):只能通过弱引用访问时的状态。当弱引用被清除的时候,就符合销毁条件。
    4.不可达(unreachable):意味着对象可以被清除了。

垃圾收集算法

标记-清除(Mark-Sweep)算法: 首先要标识出所有要回收的对象,然后进行清除。标记、清除过程效率有限,有内存碎片化问题,不适合特别大的堆;收集算法基本基于标记-清除的思路进行改进。
(内存碎片化会导致大对象无法被存放)

复制(Copying)算法: 划分两块同等大小的区域,收集时将活着对象复制到另一块区域。拷贝过程中将对象顺序放置,就可以避免内存碎片化。复制+预留内存,有一定的浪费。

标记-整理(Mark-Compact): 类似于标记-清除,但为避免内存碎片化,它在清理过程中将对象移动,以确保移动后的对象占用连续的内存空间。

那么JVM到底使用的是哪种垃圾回收算法?

分代收集

根据对象的存活周期,将内存分为几个区域,不同区域采用合适的垃圾收集算法。
新对象会分配到Eden,如果超过-XX:+PretenureSizeThreshold:设置大对象直接进入老年代的阈值。

主流的JVM都是使用分代收集的方式来管理
以hotspot为例
堆内存分为两大块,老年代(Tenured)和新生代(Eden),大小比例为2:1

新生代细分又分3个区,有S0、S1、Eden,比例为1:1:8

在这里插入图片描述
新生代算法
以下参考 原文链接:https://blog.youkuaiyun.com/weixin_40739833/article/details/80717638

新生代中98%的对象都是”朝生夕死”的,所以并不需要按照1 : 1的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的Eden(伊甸园)空间和两块较小的Survivor(幸存者)空间,每次使用Eden和其中一块Survivor(两个Survivor区域一个称为From区,另一个称为To区域)。

当进行垃圾回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。

当Survivor空间不够用时,则需要依赖其他内存(老年代)进行分配担保。

HotSpot默认Eden与Survivor的大小比例是8 : 1,也就是说Eden:Survivor From : Survivor To = 8:1:1。所以每次新生代可用内存空间为整个新生代容量的90%,而剩下的10%用来存放回收后存活的对象。

HotSpot实现的复制算法流程如下:

1. 当Eden区满的时候,会触发第一次Minor gc,把还活着的对象拷贝到Survivor From区;当Eden区再次触发Minor gc的时候,会扫描Eden区和From区域,对两个区域进行垃圾回收,经过这次回收后还存活的对象,则直接复制到To区域,并将Eden和From区域清空。

2. 当后续Eden又发生Minor gc的时候,会对Eden和To区域进行垃圾回收,存活的对象复制到From区域,并将Eden和To区域清空。

3. 部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入到老年代。

在这里插入图片描述

发生在新生代的垃圾回收成为Minor GC,Minor GC又称为新生代GC,因为新生代对象大多都具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
————————————————
版权声明:本文为优快云博主「Xucc_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/weixin_40739833/article/details/80717638

有3种情况新生代对象会进入老年代

  1. 在S0及S1之间达到一定交换次数
  2. 超过-XX:+PretenureSizeThreshold:大对象直接进入老年代的阈值
  3. 新生代内存不够时,新生成的对象也会直接进入老年代

老年代算法
复制算法在对象存活率较高的老年代会进行很多次的复制操作,效率很低,所以在栈的老年代不适用复制算法。针对老年代对象存活率高的特点,提出了一种称之为”标记-整理算法”。

发生在老年代的GC称为Full GC,又称为Major GC,其经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

我们可以认为Major GC == Full GC,他们是一个概念,就是针对老年代/永久代进行GC。因为取名叫Full就会让人疑惑,到底会不会先Minor GC。事实上Full GC本身不会先进行Minor GC,我们可以配置,让Full GC之前先进行一次Minor GC,因为老年代很多对象都会引用到新生代的对象,先进行一次Minor GC可以提高老年代GC的速度。比如老年代使用CMS时,设置CMSScavengeBeforeRemark优化,让CMS remark之前先进行一次Minor GC。
引用连接:https://blog.youkuaiyun.com/hellozhxy/article/details/80649342

垃圾回收/收集器

串行收集器 -Serial GC -XX:UseSerialGC
单个线程来执行所有垃圾收集工作,适合单处理器机器
Client模式下JVM的默认选项

串行收集器 -Serial Old -XX:+UseSerialOldGC
可以在老年代使用,它采用了标记-整理(Mark-Compact)算法,区别于新生代的复制算法

在这里插入图片描述

并行收集器 -Parallel GC -XX:+UseParallelGC
并行收集器 - Pararrel Old GC -XX:+UseParallelOldGC

server模式JVM的默认GC选择,整体算法和Serial比较相似,区别是新生代和老年代GC是并行进行,可以设置GC时间或吞吐量等值,可以自动进行适应性调整Eden,Survivor大小和MaxTenuringTheshold的值。

也称为吞吐量优先的GC:吞吐量=用户代码运行时间/(用户代码运行时间+GC时间)

-XX:ParallelGCThreads:设置用于垃圾回收的线程数。通常情况下和CPU数量相等。
-XX:MaxGCPauseMills:设置最大垃圾收集停顿时间。它的值是一个大于0的整数。
-XX:GCTimeRatio:设置吞吐量大小,它的值是一个0-100之间的整数。
-XX:+UseAdaptiveSizePolicy:打开自适应GC策略。以达到在堆大小、吞吐量和停顿时间之间的平衡点。(这个值是默认打开的)

并行收集器在垃圾回收时,也会stop the world

并发收集器-CMS(Concurrent Mark Sweep)GC -XX:+UseConcMarkSweepGC
专用老年代,基础标记-清除(Mark-Sweep)算法,设计目标是尽量减少停顿时间。

采用的标记-清除算法,存在着内存碎片化,长时间运行等情况下发生full GC,导致恶劣的停顿。

CMS会占用更多CPU资源,并和用户线程争抢。
减少了停顿时间,这一点对于互联网web等对时间敏感的系统非常重要,一直到今天,仍然有很多系统使用CMSGC

在这里插入图片描述
并行收集器 -ParNew GC -XX:+UseParNewGV
新生代GC实现,它实际是Serial GC 的多线程版本。
可以控制线程数量,参数:-XX:ParallelGCThreads
最常见的应用场景是配合老年代的CMS GC工作。参数-XX:+UseConcMarkSweepGC
在这里插入图片描述
并发收集器 -G1 -XX:+UseG1GC
针对大堆内存设计的收集器,兼顾吞吐量和停顿时间 ,JDK9后为默认选型,目标是替代CMS;
G1将对分成固定大小的区域,Region之间是复制算法,但整体上实际可看作是标记-整理算法,可以有效地避免内存碎片,红色新生代(Eden和Survior),淡蓝色老年代。找不到大内存时执行Full GC。
在这里插入图片描述

在这里插入图片描述
一般使用3种组合

  1. G1
  2. (默认)在这里插入图片描述
  3. 在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值