G1
基本概念
- card table:由于在做ygc的时候,需要找到哪些对象需要回收,那就可能需要遍历全部的old区,才能找到需要回收的对象,效率低。所以jvm设置了card table.对eden区和old区,每几个对象分为一个card。如果一个card里面有一个对象的引用指向Y区,则将card设置为dirty。再次扫描只需要扫描dirty的card。在结构上,用bitmap保存。
- CSet=collection set。一组可被回收的分区的集合。把需要回收的region,都集合起来,叫做collection set
- RSet=remebered set。每一个region中都有一个hashtable,记录了其他region中的对象到本对象的引用。使得垃圾回收不需要扫描整个堆,就可以知道谁使用了当前region中的对象,只需要扫描Rset
原理
逻辑上分为old、survivor、eden、以及humongous(大内存区,超过单个region50%),物理上,分为一个个region,分布在不同的内存地址上,所以每一个region不是固定的old区还是eden区了。
特点
- 并发收集
- 压缩空闲空间不会延长GC的暂停时间
- 更易预测GC的暂停时间
- 适用不需要实现很高吞吐量的场景
- 新老年代比例在5-60%,动态的。一般不需要手动指定,也不要手动指定。这是G1预测停顿时间的基准
- MixedGC,相当于CMS
- 当对象占用堆到达45%,启动MixedGc
- 过程:
- 初始标记STW
- 并发标记
- 重新标记STW
- 筛选回收STW,筛选最需要回收的region(垃圾最多的)
- 过程:
- -XX:initiatingHeapOccupacyPercent可以设置阈值
- 当对象占用堆到达45%,启动MixedGc
并发标记算法
三色标记法
- 白色:未被标记对象,需要回收
- 灰色:自身被标记,成员对象未被标记
- 黑色:自身和成员变量都完成了标记
漏标:
当A标记为黑色,B标记为灰色,D为白色。在并发标记阶段的时候,A已经标记为黑色了,但是删除了B对D的引用,且将A引用指向到了D,则产生了漏标。
漏标:本来是活着的对象,但是因为没有被标记到,就被回收了。
解决方法,2选一即可:
- incremental update. 增量更新,关注引用的增加。把黑色重新标记为灰色,下次重新扫描属性。(CMS用的就是这个)
- SATB(snapshot at the begining)。关注引用的删除。当B对D的引用删除时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到(G1用的是这个)
Rset与赋值的效率
由于Rset的存在,所以每次给对象赋引用的时候,就得做一些额外的操作,在Rset中做一些额外的记录(在GC中称做写屏障,这个屏障不等于内存屏障)
面试题
- 如果G1产生FGC,你该干什么?(内存不够分配了,就会产生FGC)
- 加内存
- 加cpu,提高分配回收对象效率,回收的越快,可用内存越大
- 降低mixed GC阈值 默认45%
- 为什么G1用SATB
- 删除的引用会被放到GC的栈中,下次扫描的时候,根据GC中存的引用直接找到region,再根据RSET,就可以直接找到哪些引用了当前对象,效率较高。SATB配合RSET,浑然天成
- cms的内存碎片化怎么解决
- -XX:+UseCMSCompactAtFullCollection,在FGC时进行压缩
- - XX:CMSFullGCsBeforeCompaction,在多少次FGC后进行压缩