当前位置:首页 > 文章 > 正文内容

java中的垃圾回收算法与垃圾回收器

廖万里2年前 (2022-10-27)文章72017

常用的垃圾回收算法

标记-清除

标记清除算法是一种非移动式的回收算法,分为标记 清除 2个阶段,简而言之就是先标记出需要回收的对象,标记完成后再回收掉所有标记的内存对象,如下图

java中的垃圾回收算法与垃圾回收器

可见回收后图中被标记的对象被删除回收了,但是碎片化比较严重不连续 对于下次分配大对象的时候由于内存不连续性影响比较大,而且每一次Gc的时候需要执行2个操作 1次标记 1次回收

标记-整理压缩

标记整理压缩算法是一种移动式的算法,由于上面标记清除算法导致内存不连续的问题 标记-整理算法就解决了这个问题。

java中的垃圾回收算法与垃圾回收器

工作原理也是2阶段操作而且更复杂了,首先找出(root)根地址的对象一直寻找标记是否被引用,引用了就标记一下,标记完成后把标记的对象按顺序移动排列在一起并清除掉边界的未标记的对象,这样就没有内存碎片。

缺点

  • 由于标记完成后需要移动对象 移动的过程可能会产生STW

  • 2次+调整指针

复制算法

复制算法更粗暴了,逻辑也很简单 通常直接申明了2块一样大小存储空间,每次只使用其中1块空间,当使用的这块空间不够用的时候就触发回收操作,将存活的对象copy到另一块空间中按顺序存放,可回收的就回收删除掉,这样一来就不会出现内存碎片,但是要多浪费50%的内存空间,主要用于年轻代 比如s0 s1亦是如此。

java中的垃圾回收算法与垃圾回收器

分代回收算法

根据对象的存活周期划分为新生代、老年代。因此可以根据不同年代的特点使用不同的回收算法。分代收集目前是大部分JVM

  • 新生代特点

    在新生代中大量的对象产生 又有大量的对象需要销毁,他们存活时间都比较短。基本上都是回收的时候大部分会被回收掉,只有少量的对象是存活不回收的。

    存活对象少,垃圾对象多这就比较适合使用复制算法,复制算法需要用到2块内存空间 每次只使用其中一块,在jdk8中不只是单纯的划分为s0 s1 二块存储空间,还新增了一块Eden ,s0 s1的默认大小是eden的8/1 这样设计的目的在于每次触发回收的时候把90(eden+其中1个s区)的区域中存活的对象copy到10%的存储中,理论上清除了90%的空间,这样做的好处就是不需要花50%的存储空间,只浪费了10%的空间就实现了这个算法逻辑。

  • 老年代特点

    老年代的特点就是对象存活时间都比较长,大量的存活对象就不适合像新生代一样用复制算法了 因为copy的成本太高,这种就比较适合标记清除算法,或者标记清除整理算法。

    优缺点概述

    算法名称优点缺点
    标记-清除简单位置不联系 碎片化严重 效率低 2次扫描
    标记-压缩整理没有碎片效率低 2次扫描 可能会多次重置指针
    复制算法没有碎片 简单高效浪费空间

垃圾回收器

上面的垃圾算法仅仅只是一个理论上的算法 ,正在实现这些算法的叫垃圾回收器,在工作中具体是怎么回收工作的可以不关心,但是需要了解不同的垃圾回收器是基于哪种算法实现的,有助于出现性能问题的时候有思路去参数调优,而不是盲目的问度娘。各个年轻代 老年代垃圾回收器可组合配对方式如下图所示

java中的垃圾回收算法与垃圾回收器java中的垃圾回收算法与垃圾回收器

serial串行收集器

serial回收器是一个串行单线程回收器,在进行垃圾回收的时候必须暂停用户工作线程,直到回收线程处理完成,每次回收必然会STW。比较适合跑在client端应用

java中的垃圾回收算法与垃圾回收器

ParNew收集器

ParNew回收器是新生代垃圾回收器, 就是serial的多线程版本 其它基本上serial差不多的,在ps回收器没有出来之前parNew+cms是服务器端首选

java中的垃圾回收算法与垃圾回收器

Parallel Scavenge收集器

常说的ps 收集器就算它,ps是一个新生代收集器采用复制算法,多线程并行收集。是jdk8的默认新生代回收器。

看起来和parNew有点一样 反正性能就是比它要强,在应用吞吐量方面更优秀。ps一般是和Parallel Old配合使用

java中的垃圾回收算法与垃圾回收器

Serial Old收集器

Serial Old收集器是Serial的老年代版本,同样它也是单线程收集,基于标记-整理算法,工作原理可以参考serial。

Parallel Old收集器

parallel old收集器是ps的老年代版本 是多线程收集器 基于标记-整理算法 弥补了serial old单线程的不足,工作原理参考ps收集器工作流程图。ps+po是jdk8默认的组合 也是我在项目中实践最多的组合。

CMS收集器

cms从jdk1.4开始引入,算是里程碑GC产品,开启了Java领域并发(注意并发与并行parallel的区别 并发是值回收垃圾的时候和用户线程一起干活,并行是指多个GC线程同时回收 )回收的方案。是一个优秀的老年代垃圾回收器。

cms从名字就能看出来是基于并发的 标记-清除算法实现的回收器,它的回收流程分为 初始标记-并发标记-重新标记-并发清除 4个阶段。

  1. 初始标记 (initial mark)
    只是标记GC Root 根对象 会stw 但是由于只是标记了gc roots 所有很快

  2. 并发标记
    根据第1阶段的结果继续往下标记 这个阶段是并发的 不影响用户线程

  3. 重新标记
    为什么会有重新标记这个阶段?是因为并发标记的时候 由于用户线程还在运行 可能产生了新的垃圾 所以需要在标记一次,当然由于第2阶段标记过一次了,这一次理论上会很快 这个阶段会STW

  4. 并发清除
    清理需要回收的对象 不影响用户线程使用。cms有个开关(-XX:CMSFullGCsBeforeCompaction=0)默认是开启碎片整理,由于cms清理后的空间也是有碎片存在的,所以一次清理就会整理一次碎片。此阶段用户线程同样会产生新的垃圾 目前没有解决清除 网上叫为浮动垃圾

所以cms只有在并发标记和并发清除阶段是不影响用户线程停顿的。初始标记 和 重新标记 也是划分的区域标记的,总体上能跟控制gc停顿时间 提高用户体验,工作原理如下

java中的垃圾回收算法与垃圾回收器

当老年代内存使用到92%(-XX:CMSInitiatingOccupancyFraction=92)之后出触发cms回收一次,如果cms在回收期间中 剩余的内存不够用户工作线程使用了(报异常Concurrent Mode Fail) 那么serial old回收器就成了紧急替补队员立即进行回收一次,当然停顿的时间就更长了。由于cms部分阶段是用户线程和gc线程一起工作,如果启动阈值设置得太高,容易导致用户工作线程不够用触发cmf异常,性能反而降低。

G1收集器

G1垃圾回收器可以同时支持年轻代、老年代,G1并没有在物理分区隔离,上面的提到的垃圾回收器都是物理上进行分区的,G1是由一块一块大小相同的region组成,虽然没有物理上进行分区,但是依然保留了年轻代 老年代的概念。回收流程有点类似cms。也是分为初始标记并发标记最终标记筛选回收 4个阶段。

Region的大小可以通过G1HeapRegionSize参数进行设置,其必须是2的幂,范围允许为1Mb到32Mb。基于堆内存的初始值和最大值的平均数计算分区的尺寸,平均的堆尺寸会分出约2000个Region。分区大小一旦设置,则启动之后不会再变化。region之间采用复制算法,因此不容易产生内存碎片。每个Region都有一个Remembered Set。当对引用进行写操作的时候,G1检查该引用的对象是否在别的region中,是的话,则通过CardTable把相关引用信息存到被引用对象的Remembered Set中。当进行内存回收时,把RememberSet加入到GC Roots根节点的枚举范围。这样就可以保证不全堆扫描也不会有遗漏。 内存结构如下

java中的垃圾回收算法与垃圾回收器

  1. Survivor regions(年轻代-Survivor区)

  2. Old regions(老年代)

  3. Humongous regions(巨型对象区域) 占用了Region容量的50%以上对象 巨型对象比较大 一般在并发标记阶段如果可以回收就直接回收了。

  4. Free resgions(未分配区域,也会叫做可用分区)-上图中空白的区域

G1之所以这里厉害在于它用到了一些数据结构的技巧

TLAB(Thread Local Allocation Buffer)本地线程缓冲区

PLAB(Promotion Local Allocation Buffer) 晋升本地分配缓冲区

Collecion Sets(CSets)待收集集合

Card Table 卡表

Remembered Sets(RSets)已记忆集合

回收流程大致如下

  1. 初始标记

    只是标记GC Roots根对象 会stw

  2. 并发标记

    从上一步标记的GC Roots开始计算可达性分析并标记 这阶段耗时但是是并发的 不影响用户线程使用

  3. 最终标记
    上一步执行的过程中产出的变动再一次计算和标记 会stw 短暂的停顿,JVM将这段时间对象变化记录到Remembered Set Log中,在最终标记阶段把Remembered Set Log合并到Remembered Set中。

  4. 筛选回收
    为什么多了一步筛选再回收,在于G1在收集的时候会优先回收比较有价值的region区域,垃圾对象比较多 存活对象比较少的region就算是有价值的 这样就能有效的提高回收效率。因为优先回收掉有价值的region而不是一下全部把堆中的全部垃圾回收完,所以回收的时间基本上能够把控。这个阶段是并行操作但是会有短暂的STW基本感知不到。

JDK10 之前的G1中的GC只有YoungGC,MixedGC。FullGC处理会交给单线程的Serial Old垃圾收集器。

zgc收集器
Shenandoah


本文链接:https://www.kkkliao.cn/?id=153 转载需授权!

分享到:

添加博主微信共同交流探讨信息差网赚项目: 19528888767 , 请猛戳这里→点我添加

版权声明:本文由廖万里的博客发布,如需转载请注明出处。

“java中的垃圾回收算法与垃圾回收器” 的相关文章

“双11”,如何守住钱袋子?

“双11”,如何守住钱袋子?

“双十一”快到了,“剁手”的大斧已高高举起。购物车收藏83件,有的商品开启定价预售模式小姐姐的化妆品要不少钱呀,也不知比平时便宜多少最近几天,同事们都在热议“双十一”。 今年的“双十一”跟以往相比有新变化,比如,缩短预售时间、扩容购物车、差价一键退,不少平台还从晚上8点开始销售等。自从2009年开始...

美设备大厂接连表态,反转出现了,外媒:华为将“打”出和平

美设备大厂接连表态,反转出现了,外媒:华为将“打”出和平

华为5G的横空出世,一举打破了美国数十年的通信霸权,也首次将中国通信带到了全球最顶端的位置,堪称是中国人的骄傲。然而,这却引起了老美的忌惮,它为了巩固自己的科技霸权地位,近些年频繁修改芯片规则,妄图通过断供来放倒华为。大家都知道,技术封锁是美帝霸凌主义惯用的手段,且屡试不爽,日本东芝和法国阿尔斯通的...

每晚泡脚15分钟,五年下来会有哪些变化?

每晚泡脚15分钟,五年下来会有哪些变化?

剑心学者10月07日关注我是每到秋季与冬季才开始泡脚,尽量做到每晚都泡。当然经期除外。每次用艾叶、生姜、花椒煮沸后加水泡15到20分钟左右。泡到全身发热为止。坚持两年了。我身体湿气较重,随时舌头都有齿痕,夏天怕热冬天怕冷,手脚冰凉的。现在最大改变就是晚上睡觉不穿袜子,脚也不冰凉。还是有一定的效果。当...

netcore有好用的word(docx)、excel(xlsx)及pdf 处理库吗?

如题,所有需求都基于开源免费库基础word主要用来做模版替换,能有docx转pdf最好excel主要用来导入导出,能生成导入模版文件,能设置每个导入模版的下拉框数据(能从数据库读数据)pdf主要用来添加水印文件或者图片。在此感谢分享...

圆周率已经算到了62.8万亿位,再算下去有什么意义?

圆周率已经算到了62.8万亿位,再算下去有什么意义?

综述大家知道,圆的周长与直径的比值就是圆周率,用希腊字母表示也就是π。π是一个无限不循环的无理数,在小数点之后存在着无限多个数字,并且不会循环。令人惊讶的是,就算已经证明了π的小数点之后的数字是无穷的,仍然有不少科学家们想要把它继续算下去。最新成果显示,瑞士的一名研究人员利用一台超级计算机,耗时19...

小米12SPro深度体验评测,什么叫“水 桶 旗 舰”啊?

小米12SPro深度体验评测,什么叫“水 桶 旗 舰”啊?

首先,依然是祖传一句话评价:补齐了唯一短板的水桶旗舰。其实就像年初的时候评价小米12Pro一样,今年的12系列看得出小米是在努力的优化体验,而不是单纯的堆叠参数,所以更注重手感的12和12S,以及徕卡加持下算法提升、影调有明显改善的小米12S Ultra便应运而生,至于今年的12Pro和12S Pr...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。