开启生长之旅!这是我参与「日新计划 12 月更文挑战」的第28天,点击检查活动概况

上篇文章浅显易懂JVM(十一)之怎么判别目标“已死”现已浅显易懂的解析JVM是怎么评判目标不再运用,不再运用的目标将变成“废物”,等待收回

废物收回算法有多种,适用于不同的场景,不同的废物搜集器运用不同的算法

本篇文章将环绕废物收回算法,浅显易懂的解析废物收回分类以及各种废物收回算法

废物收回算法

废物收回分类

废物搜集器有着多种GC方法,不同的GC方法有自己的特点,收回的堆内存部分也不同

堆内存分为新生代和老时代,新生代存储“年青”的目标,老时代存储“老”或内存大的目标,目标年纪由阅历多少次GC来判别

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

  • 部分搜集(Partial GC): 搜集目标是部分空间

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

符号-铲除算法

Mark-Sweep

符号:从GCRoots开始遍历引证链,符号一切可达目标 (在目标头中符号)

铲除:从堆内存开始线性遍历,发现某个目标没被符号时对它进行收回

深入浅出JVM(十二)之垃圾回收算法

符号-铲除算法完成简略、不需求改动引证地址,可是需求两次遍历扫描功率不高,而且会呈现内存碎片

留意:这儿的铲除并不是真正意义上的收回内存,只是更新闲暇列表(符号这块内存地址为闲暇,后续有新目标需求运用就掩盖)

仿制算法

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区(写错)

深入浅出JVM(十二)之垃圾回收算法

深入浅出JVM(十二)之垃圾回收算法

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

仿制算法不需求遍历,而且不会产生内存碎片,可是会浪费survive区一半的内存,移动目标时需求STW暂停用户线程,而且仿制后会改动引证地址(hotspot运用直接指针访问,还要改动栈中reference履行新引证地址)

假如仿制算法中目标存活率太高会导致十分消耗资源,因此一般只要新生代才运用仿制算法

符号-收拾算法

Mark-Compact

符号:从GCRoots开始遍历引证链,符号一切可达目标(在目标头中符号) (与符号-铲除算法共同)

收拾:让一切存活目标往内存空间一端移动,然后直接纳拾掉边界以外的一切内存

深入浅出JVM(十二)之垃圾回收算法

符号-收拾算法不会呈现内存碎片也不会浪费空间,可是功率低(比符号-铲除还多了收拾功用),移动目标导致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虚拟机》

本篇文章将被收入JVM专栏,觉得不错感兴趣的同学能够保藏专栏哟~

觉得菜菜写的不错,能够点赞、关注支撑哟~

有什么问题能够在评论区交流喔~