设计目标,尽可能少或者不需要调优,
只要记住MaxGCPauseMillis=N
记忆集是一种用于记录从非收集区指向收集区的数据结构。记录了谁引用了我
作用:避免把整个老年代加进GC Root的扫描范围
卡表:当判断一个卡页中有存在对象的夸代引用时,将这个页标记为脏页
https://blog.csdn.net/qq_39432354/article/details/122851456
G1收集器原理与分析 - 知乎
https://zhuanlan.zhihu.com/p/337029344
https://zhuanlan.zhihu.com/p/337029344
粗犷的记录力度会节省记忆集的存储和维护成本
字长精度:即跨代指针
对象精度:每个记录精确到一个对象,对象里有字段含有跨代指针
卡精度:每个记录精确到一块内存区域,该区域有对象含有跨代指针
卡精度:用称实现为“卡表”的数据结构去实现记忆集。
CARD_TABLE[this address >> 9] = 0
一个卡表包含多个对象,只要有一个对象存在跨代指针,那就将卡表的数组元素标识标识为1,代表变脏(Dirty)
卡表为什么使用Byte不用bit存储Dirty?
cpu没有直接存储一个bit的指令,要用big的话就要不得不i熬好几条shift+mask指令
那么记忆集怎么维护呢?
动作放到每个赋值操作之中
那能否通过类似与AOP的方式,在赋值操作添加一个后置操作呢?
事实上就是这么干的
在HotSpot虚拟机里通过写屏障(Write Barrier)
代码清单:写后屏障更新卡表
void oop_field_store(oop* field, oop new_value) {
// 引用字段赋值操作
*filed = new_value;
//写后屏障,在里面完成卡表状态的更新
post_write_barrier(field, new_value);
}
卡表:
https://www.jianshu.com/p/32d7d1bbfdd6
什么叫"伪共享"问题?
处理器缓存一个缓存单位是64字节,称之为缓存行。当更新了多个处理器共享的缓存行,缓存就会失效。什么叫“伪共享”问题呢?一个缓存行存了很多边拉你个,其中两个是两个变量a和变量b, 线程1一直更新a,线程2一直更新b,就会导致缓存行一直失效。就好像是两个线程在更新同一个共享变量一样,性能下降。这就是伪共享。
卡表一个字节对应了(64 x 512字节)32k的内存。
不同处理器频繁更新这32K内存,从而频繁更新缓存行频繁失效,影响性能。
怎么解决伪共享问题?
判断未被标记过时才将其标记为变脏,卡表更新逻辑如下:
if (CARD_TABLE[this address >> 9] != 0) {
CARD_TABLE[this address >> 9] = 0;
}
虚拟机也提供了类似的逻辑,参数:-XX:+UseCondCardMark。开启会增加一个额外的判断的开销,但能解决伪共享问题
解决并发标记“对象消失”的问题?
记忆集
内存布局
完全年轻代GC
老年代GC
三色标记:黑白灰
并发漏标记问题
解决方案:
GC流程
https://zhuanlan.zhihu.com/p/59861022
Mixed GC
和fully young gc同样的算法
STW Parallel Copying
G1并发标记阶段如何保证收集线程和用户线程互不干扰运行?
如何建立停顿预测模型?
GC过程
ZGC:
特性:
- 非常恐怖的低延迟
- 并发压缩
- 单一代(不分代)
- 基于Rigion(Zpage)
并发拷贝
染色指针
1.染色指针
2.虚拟内存
3.读屏障
问题:
- 不能使用Oops
- RSS show 3x size
-
- -Xms16g -> RSS ~= 50G
2.OOM killer
- -Xms16g -> RSS ~= 50G
怎么染色 load barrier
- 检查指针的颜色
- 指针是否处于正确状态
- 如果颜色错误 -> show path
- 修正颜色,执行必要的行为
https://www.jianshu.com/p/4e4fd0dd5d25