深入浅出JVM之垃圾回收算法

createh51周前 (05-16)技术教程11

垃圾回收算法

垃圾回收分类

垃圾收集器有着多种GC方式,不同的GC方式有自己的特点,回收的堆内存部分也不同

堆内存分为新生代和老年代,新生代存储“年轻”的对象,老年代存储“老”或内存大的对象,对象年龄由经历多少次GC来判断

其中整堆收集时不仅会回收整个堆还会回收元空间(直接内存)

  • 部分收集(Partial GC): 收集目标是部分空间
    • 新生代收集(Minor GC/ Young GC):收集新生代Eden、Survive to、Survive from区
    • 老年代收集(MajorGC/Old GC):收集老年代
    • 混合收集(Mixed GC):收集整个新生代和部分老年代
  • 整堆收集(Full GC): 整个堆 + 元空间

标记-清除算法

Mark-Sweep

标记:从GCRoots开始遍历引用链,标记所有可达对象 (在对象头中标记)

清除:从堆内存开始线性遍历,发现某个对象没被标记时对它进行回收

标记-清除算法实现简单、不需要改变引用地址,但是需要两次遍历扫描效率不高,并且会出现内存碎片

注意:这里的清除并不是真正意义上的回收内存,只是更新空闲列表(标记这块内存地址为空闲,后续有新对象需要使用就覆盖)

复制算法

Copying

Survive区分为两块容量一样的Survive to区和Survive from区

每次GC将Eden区和Survive from区存活的对象放入Survive to区,此时Survive to区改名为Survive from区,原来的Survive from区改名为Survive to区 保证Survive to区总是空闲的

如果Survive from区的对象经过一定次数的GC后(默认15次),把它放入老年代

流程图

注意:图中的dean为Eden区(写错)

注意:最终的survive from区存活对象占用的内存应该是(那两块蓝色)挨着一起的,图中为了标识字分开来了

复制算法不需要遍历,并且不会产生内存碎片,但是会浪费survive区一半的内存,移动对象时需要STW暂停用户线程,并且复制后会改变引用地址(hotspot使用直接指针访问,还要改变栈中reference执行新引用地址)

如果复制算法中对象存活率太高会导致十分消耗资源,因此一般只有新生代才使用复制算法

标记-整理算法

Mark-Compact

标记:从GCRoots开始遍历引用链,标记所有可达对象(在对象头中标记) (与标记-清除算法一致)

整理:让所有存活对象往内存空间一端移动,然后直接清理掉边界以外的所有内存

标记-整理算法不会出现内存碎片也不会浪费空间,但是效率低(比标记-清除还多了整理功能),移动对象导致STW和改变reference指向

如果不移动对象会产生内存碎片,内存碎片过多,将无法为大对象分配内存

还有种方法:多次标记-清除,等内存碎片多了再进行标记-整理

分代收集算法


标记清除mark-sweep

复制copying

标记整理mark-compact

速度

GC后是否需要移动对象

不移动对象

移动对象

移动对象

GC后是否存在内存碎片

存在内存碎片

不存在内存碎片

不存在内存碎片

需要移动对象 意味着 要改变改对象引用地址 也就是说要改变栈中reference指向改对象的引用地址,并且会发生STW停顿用户线程

当空间中存在大量内存碎片时,可能导致大对象无法存储

分代收集算法 : 对待不同生命周期的对象可以采用不同的回收算法(不同场景采用不同算法)

年轻代: 对象生命周期短、存活率低、回收频繁,采用复制算法,高效

老年代: 对象生命周期长、存活率高、回收没年轻代频繁,采用标记-清除 或混用 标记-整理

增量收集算法

mark-sweep、copying、mark-compact算法都存在STW,如果垃圾回收时间很长,会严重影响用户线程的响应

增量收集算法: 采用用户线程与垃圾收集线程交替执行

增量收集算法能够提高用户线程的响应时间,但存在GC、用户线程切换的开销,降低了吞吐量,GC成本变大

分区算法

堆空间越大,GC时间就会越长,用户线程响应就越慢

分区算法: 将堆空间划分为连续不同的区,根据要求的停顿时间合理回收n个区,而不是一下回收整个堆

每个区独立使用,独立回收,根据能承受的停顿时间控制一次回收多少个区

G1收集器以及两块低延迟收集器Shenandoah、ZGC就使用到这种分区算法

总结

本篇文章围绕垃圾回收算法,深入浅出解析垃圾回收分类、标记清除、复制、标记整理、分代收集、增量收集、分区算法等多种算法

从垃圾回收空间上划分可以分为Full GC回收整个堆加上元空间、Minor GC回收新生代、major GC回收老年代、mixed GC回收新生代加老年代

标记清除算法会遍历引用链标记可达对象从而清理不可达对象,会产生内存碎片,速度一般

复制算法不会产生内存碎片,并且速度很快,但是会浪费survivor区一半空间,并且会移动对象

标记整理算法在标记清理基础上增加整理功能,不会产生内存碎片,但会移动对象,速度慢

不同的算法有不同的特点,应对新生代可以使用复制算法,应对老年代可以使用标签清除/整理算法

增量收集使用GC、用户线程交替执行,虽然降低用户响应,但线程切换、吞吐量下降会增加GC成本

分区算法将堆内存划分为多个区,根据能够接收的停顿时间来回收性价比高的多个区,停顿时间既在能够接收时间内,又能够回收性能比高的区

相关文章

图解Java垃圾回收机制,写得非常好

什么是自动垃圾回收?自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用...

Java的垃圾回收(Garbage Collection)机制

(原文2006年发在CSDN上,ID是beepbug。因为是发表在CSDN上,内容可能有点偏深奥。如果有不明白处,可以在评论区提出,或私信我。)一.谁在做Garbage Collection? 一种流...

JVM内存清洁工:垃圾回收算法如何让Java程序跑得更快更稳?

在Java的世界里,程序运行时的内存就像一间不断产生垃圾的房间。如果没有“清洁工”及时清理,垃圾堆积会导致房间无法容纳新物品,最终程序崩溃。而JVM的垃圾回收(GC)机制,正是这位隐形的“扫地僧”,默...

「Java入门」十五 垃圾回收机制

今天来自Java300课程的垃圾回收机制,有视频详解在这里,点击「链接」就可以看到了哦,有需要配套视频资料的小伙伴也可以点击「链接」哦。垃圾回收机制(Garbage Collection)Java引入...

Java虚拟机中的垃圾回收算法:那些让你的内存“焕然一新”的秘密

Java虚拟机中的垃圾回收算法:那些让你的内存“焕然一新”的秘密在Java的世界里,Java虚拟机(JVM)就像一个精明的管家,它不仅管理着我们的代码执行,还负责清理内存中不再需要的对象,这就是我们所...

JVM03——四种垃圾回收算法,你都了解了哪几种

在之前的文章中,已经为各位带来了JVM的内存结构与堆内存的相关介绍,今天将为为各位详解JVM垃圾回收与算法。关注我的公众号「Java面典」了解更多 Java 相关知识点。如何确定垃圾想要回收垃圾,必须...