JVM优化四:垃圾收集

一、垃圾收集算法

1,分代收集理论

  • 原理

  • 堆内存因对象存活周期不同分为新生代和老年代,分代收集理论就是根据不同年代的特点选择合适的垃圾收集算法,从而提高gc效率。

2,标记-复制算法

  • 原理

  • 将堆内存分为大小相等的两块,每次只使用其中的一块。当这一块的内存使用完后,将还存活的对象复制到另外一块去,在把已满空间内的对象全部清理掉。

  • 图示

  • 优缺点

  • 优点:清理完后内存整齐,几乎不会有内存碎片。

  • 缺点:每次只能使用内存的一般,内存利用率减半。

3,标记-清除算法

  • 原理

  • 标记存活对象,统一回收所有未被标记的对象。

  • 图示

  • 优缺点

  • 优点:内存利用占满。

  • 缺点:内存过大,存活对象较高的话,标记效率不高;清理过后可能会产生大量的内存碎片。

4,标记-整理算法

  • 原理

  • 标记存活对象,让所有存活对象向一端移动,然后清除掉端边界以外的所有对象。

  • 图示

  • 优缺点

  • 优点:内存利用占满,内存整齐,几乎不会有碎片产生。

  • 缺点:如果内存过大,存活对象较多,标记+移动效率都不高。

二、垃圾收集器

1,Serial收集器

  • 简介

  • 单线程收集器,整个收集过程STW。

  • 新生代采用复制算法,老年代采用标记-整理算法。

  • 老年代收集器可以作为CMS收集器的后备方案。

  • 收集流程

  • 相关参数

  • -XX:+UseSerialGC:新生代启用Serial收集器。

  • -XX:+UseSerialOldGC:老年代启用Serial收集器。

2,Parallel收集器

  • 简介

  • 多线程收集器,整个收集过程STW,默认收集线程数==cpu核数。

  • jdk1.8默认的新生代和老年代收集器。

  • 新生代采用复制算法,老年代采用标记-整理算法。

  • 关注的是吞吐量(更高效率的利用cpu去gc)。

  • 收集流程

  • 相关参数

  • -XX:+UseParallelGC:新生代启用Parallel收集器。

  • -XX:+UseParallelOldGC:老年代启用Parallel收集器。

3,ParNew收集器

  • 简介

  • 类似Parallel收集器,主要是用来配合CMS进行垃圾回收。

  • 采用复制算法,只能收集新生代内存。

  • 收集流程

  • 相关参数

  • -XX:+UseParNewGC:新生代启用ParNew收集器。

4,CMS收集器

  • 简介

  • 真正意义上的并发收集器,实现了垃圾收集线程与用户线程同时工作。

  • 关注的更多是获取最短的回收停顿时间,注重用户体验。

  • 采用标记-清除算法,只能回收老年代内存。

  • 收集流程

  • 初始标记:stw。标记的是gc roots直接引用的对象,速度很快。

  • 并发标记:用户线程和垃圾收集线程并发执行。从初始标记对象开始遍历标记整个gc roots对象图的对象。由于用户线程也在执行,此过程就可能会存在多标、漏标、新增对象问题。

  • 重新标记:stw。解决并发标记过程中的多标、漏标、新增对象问题。主要是解决漏标问题。

  • 并发清理:用户线程和垃圾收集线程并发执行。清理内存中未被标记的对象。由于用户线程也在执行,此过程就可能会存在新增对象问题。

  • 并发重置:用户线程和垃圾收集线程并发执行。重置本轮gc的所有标记数据,清理标记。

  • 相关参数

  • -XX:+UseConcMarkSweepGC:老年代启用CMS收集器。

  • -XX:+CMSParallelInitialMarkEnable:设置初始标记过程多线程执行,缩短stw时间。

  • -XX:+CMSParallelReMarkEnable:设置重新标记过程多线程执行,缩短stw时间。

  • -XX:CMSInitiatingOccupancyFraction:设置触发full gc的老年代内存占用比例,默认92%。

  • -XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,jvm仅会在第一次使用设定值,后续会自动调整。

5,G1收集器

  • 简介

  • 将java堆分为多个大小相等的region,最多2048个,一般region大小等于堆大小除以2048。

  • 保留了分代概念,但不再是物理划分了,而是一个个region。

  • 有专门分配大对象(一个对象超过了一个region大小的50%)的region叫Humongous区。一个Humongous对象一般会横跨多个region存放。

  • region的区域功能可能会动态变化。一个region之前可能是新生代,可能一次gc之后就会变为老年代。

  • 收集流程

  • 初始标记:stw。标记的是gc roots直接引用的对象,速度很快。

  • 并发标记:用户线程和垃圾收集线程并发执行。从初始标记对象开始遍历标记整个gc roots对象图的对象。由于用户线程也在执行,此过程就可能会存在多标、漏标、新增对象问题。

  • 最终标记:stw。解决并发标记过程中的多标、漏标、新增对象问题。主要是解决漏标问题。

  • 筛选回收:stw。对每个region的回收价值和成本计算排序,根据用户期望的stw停顿时间,制定回收计划,优先回收一部分region,达到停顿阈值后,停止回收,剩余的垃圾region待下次gc回收。

  • GC分类

  • Young GC:并不是现有Eden区放满就马上触发,G1会计算现在回收Eden区大概需要的时间,如果远远小于预期最大停顿时间,会增加年轻代的region继续存放新对象,不会马上做Young GC,直到下一次Eden放满,重复计算判断过程,当计算的回收时间接近预期最大停顿时间时,触发Young GC。

  • Mixed GC:老年代的内存占有率达到-XX:InitiatingHeapOccupancyPercent参数设定的值则触发Mixed GC。回收所有的年轻代和部分老年代(根据预期停顿时间决定回收多少)以及大对象区。

  • Full GC:G1在Mixed GC过程中需要把各个region中的存活对象复制到别的region,如果没有足够大的region可以存放,就会触发Full gc。此过程stw,采用单线程进行垃圾收集,非常耗时。

  • 相关参数

  • -XX:+UseG1GC:启用G1收集器

  • -XX:G1NewSizePercent:设置新生代初始内存占用比例,默认5%。

  • -XX:G1MaxNewSizePercent:设置新生代最大内存占用比例,最大不能超过60%。

  • -XX:MaxGCPauseMills:设置预期停顿时间,默认200ms。

  • -XX:InitiatingHeapOccupancyPercent:设置Mixed GC触发的老年代空间在整堆的占用比例阈值,默认45%。

  • -XX:G1MixedGCLiveThresholdPercent:设置一个region回收的存活对象比例,默认85%。低于这个值才会回收。

三、三色标记算法

1,原理

把gc roots可达性分析遍历过程中遇到的对象,按照"是否访问过"这个条件标记成三种颜色。

  • 黑色:表示对象及其所有的引用都已经被垃圾对象扫描过,是完全存活的对象,不会被再次扫描。

  • 灰色:表示对象已经被垃圾收集器扫描过,但这个对象至少还有一个引用没有被扫描。

  • 白色:表示对象尚未被垃圾收集器扫描过。可达性算法刚开始时,所有对象都是白色的,分析结束时还是白色的对象即为不可达对象,也就是垃圾对象。

2,应用

  • CMS垃圾收集过程一重新标记。

  • 多标解决:下一次gc清理。

  • 新增对象解决:直接标记为黑色,使其变为浮动垃圾,下一次gc清理。

  • 漏标解决:写屏障+增量更新算法解决。黑色对象插入新的白色对象的引用关系后,将新插入的引用记录下来,并发标记过后,再以这些记录中的黑色对象为根,重新扫描标记一次。

  • G1垃圾收集过程一最终标记。

  • 多标解决:下一次gc清理。

  • 新增对象解决:直接标记为黑色,使其变为浮动垃圾,下一次gc清理。

  • 漏标解决:写屏障+SATB(原始快照)。将要插入引用的白色对象直接标记为黑色,使其在本轮gc清理中活下来(变其为浮动垃圾),并发标记过后,重新扫描标记即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值