垃圾回收机制GC

1. GC相关

1.1 什么是垃圾

没有任何引用指向的一个或者一堆对象

1.2 如何定位垃圾

  1. 引用计数(RefrenceCount): 计数变为0的时候就是垃圾,回收走
    问题:循环引用

  2. 根可达算法(RootSearching):从根开始找,没有关联关系,回收走。
    哪些内容算root,见下图
    在这里插入图片描述

1.3 垃圾回收算法

  1. Mark-Sweep(标记清除)
    算法相对简单,存活对象较多的情况下效率较高。
    先标记,再清除,两次扫描,效率较低,容易产生碎片
    在这里插入图片描述
  2. Copying(拷贝)
    适用于存活对象较少的情况,只扫描一次,效率较高,且没有碎片。
    空间浪费,异动复制对象,需要调整对象引用。
    在这里插入图片描述
  3. Mark-Compack(标记压缩)
    不会产生碎片,方便分配内存,不会产生内存减半。
    扫描两次,需要移动对象,效率偏低
    在这里插入图片描述

2. JVM内存分代模型(用于分代垃圾回收算法)

2.1 部分垃圾回收器使用的模型

  • Epsiolon、ZGC、Shenandoah 之外的GC都使用逻辑分代模型
  • G1 是逻辑分代,物理不分代
  • 除此之外不仅逻辑分代,而且物理分代

2.2 新生代 + 老年代 + 永久代(1.7)Perm Generation / 元数据区(1.8)Metaspace

  • 永久代存放元数据(class信息)
  • 永久代必须制定大小限制;元数据区可设置也可以不设置,无上限,受限于物理内存
  • 字符串常量1.7 在永久代,1.8在堆中

2.3 新生代 = Eden + 2个Suvivor区

  • YGC回收之后,大多数的对象会被回收,活着的进入S0
  • 再次YGC,活着的对象eden+s0 -> s1
  • 再次YGC,eden + s1 -> s0
  • 年龄足够 进入老年代
    Parallel Scavenge:15
    CMS:6
    G1:15
  • s区装不下,进入老年代

2.4 老年代

  • 老年代满了,FGC (Full GC)

2.4 GC调优

  • 尽量减少FGC
    在这里插入图片描述

3. 常见的垃圾回收器

在这里插入图片描述

3.1 常见垃圾回收器

3.1 Stop-The-World(STW)

GC在后台自动发起和自动完成的,在用户不可见的情况下,在safe point情况下,将正常的工作线程全部停掉,即GC停顿,会带给用户不良的体验;

3.1.1 为什么要Stop-The-World

为了确保快照的一致性,不可以出现分析过程中对象引用关系还在不断变化的情况。
Stop-The-World是导致GC卡顿的重要原因之一。

3.2 常见垃圾回收器

3.2.1 Serial / SerialOld

Serial 年轻代
SerialOld 老年代,采用标记整理算法
串行回收,单线程、简单高效
垃圾回收时,必须暂停其他所有的工作线程,直到它结束(Stop The World)
年轻代 串行回收

在这里插入图片描述

3.2.2 Parallel Scavenge / ParallelOld

Parallel Scavenge(PS) 年轻代,采用复制算法
ParallelOld(PO)老年代,采用标记整理算法
并行回收,多线程收集器
默认垃圾回收器组合

在这里插入图片描述

3.2.3 ParNew

ParNew 年轻代
配合CMS的并行回收
同PS类似,PS的扩展版本,增加CMS扩展

3.2.4 CMS

老年代
标记清除算法,并发收集
垃圾回收与应用程序同时进行,降低STW的实现

在这里插入图片描述

3.2.5 G1

三色标记+SATB
逻辑分代,物理部分带
目标是用在多核、大内存的机器上
并发收集、并发标记、并发回收
大多数情况下可以实现制定的GC暂停时间,同时保持较高吞吐量
G1的内存区域不是固定的E或者O

  • Region
    大小是2的倍数,最大32
  • 内存模型
    Old 老年代区
    Survivor 存活区
    Eden 新生代区
    Humoungous 大对象区,超过region 50%的对象
  • Collection Set(CSet)
    一组可被回收的分区(card)的集合。
    再CSet中存活的数据会再GC过程中被移动到另一个可用分区,CSet中的分区可以来自Eden空间、survivor空间、或者老年代。
    CSet会占用不到真个堆空间的1%
  • RememberedSet(RSet)
    每一个region里面都有一个hash表,记录着其他region中的对象到本region的引用。
    RSet的价值在于,使得垃圾收集器不需要扫描整个堆找到谁引用了当前分区中的对象,只需要扫描RSet即可。
  • 新老年代比例
    5%-60%
    动态,一般不用手工指定,也不要手工指定,因为这是G1预测停顿时间的基准。
  • GC何时触发
    1.YGC
    Eden空间不足
    多线程并行执行
  1. FGC
    Old空间不足
    System.gc()
  • G1中的MixedGC
    相当于CMS
    XX:InitiatingHeapOccupacyPercent 默认值45%
    当O超过这个值时,启动MixedGC

  • MixedGC过程
    初始标记 STW
    并发标记
    最终标记
    筛选回收

-FullGC
JAVA 10以前是串行FullGC,之后是并行FullGC
在这里插入图片描述

3.2.6 ZGC

ColoredPointers + LoadBarrier
后续补充

3.3 一些概念

3.3.1 Card Table

由于做YGC时,需要扫描整个OLD区,效率非常低,所以JVM设计了CardTable, 如果一个OLD区CardTable中有对象指向Y区,就将它设为Dirty,下次扫描时,只需要扫描Dirty Card
在结构上,Card Table用BitMap来实现

3.3.2 三色标记算法

黑色:自身和成员变量均已标记完成
灰色:自身被标记,成员变量未被标记
白色:未被标记的对象

3.3.3 漏标

在并发标记过程中,黑色指向了白色,如果不对黑色重新扫描,则会漏标。
在这里插入图片描述
在这里插入图片描述

3.3.4 如何解决漏标

1、incremental update - 增量更新,关注引用的增加
把黑色重新标记为灰色,下次重新扫描属性(CMS使用)

2、SATB snapshot at the beginning - 关注引用的删除
当B->D消失时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到(G1使用)

3.3.5 为什么G1使用SATB

灰色->白色 引用消失时,如果没有黑色指向白色,引用会被push到堆栈;下次扫描时,拿到这个引用,由于G1有RSet存在,不需要扫描整个堆去查找指向白色的引用,效率比较高,SATB配合RSet。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值