这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
CMS
- 初始标记:STW找到根对象,耗时较短
- 并发标记:应用线程和GC线程并发执行,将根对象引用的其它对象找出来,耗时较长。在此过程中,会出现之前不可用对象重新变成可用对象的情况。
- 重新标记:STW找到在并发标记过程中产生状态变化的对象,进行重新标记,耗时较短
- 并发清理:应用线程和GC线程并发执行,清理垃圾对象,在此过程中会重新产生新的垃圾(浮动垃圾),交给下次GC清理。
G1
参考文章:g1gc
- 垃圾优先 Garbage First
- G1是一种服务端应用使用的垃圾回收器,目标是用在多核、大内存的机器上,它在大多数情况下可以实现指定的GC暂停时间,同时还能保持较高的吞吐量。
G1:分而治之(逻辑分代、物理不分代)
特点
- 并发收集
- 压缩空闲时间不会延长GC的暂停时间
- 更易预测的GC暂停时间
- 适用于不需要实现很高的吞吐量的场景
G1的内存区域不是固定的E或者O
GC算法的基本概念
- Card Table(卡表)
由于做YGC时,需要扫描整个old区,判断某个对象是否被引用,效率非常低,如果有个old区Card Table中有对象指向Y区,就将它设为 dirty,下次扫描时,只需要扫描Dirty Card。在结构上,Card Table用BitMap来实现。
-
CSet = Collection Set
- 一组可以被回收的分区的集合
- 在CSet中存活的数据会在GC过程中被移动到另一个可用分区,CSet中的分区可以来自Eden空间、Survivor空间、或者老年代。CSet会占用不到整个堆空间的1%大小。
-
RSet = Remembered Set
- 记录了其它 Region 中的对象到本 Region 的引用
- RSet的价值在于:使得垃圾回收器不需要扫描整个堆找到谁引用了当前分区中的对象,只需要扫描RSet即可。
- RSet与赋值的效率
- 由于RSet的存在,那么每次给对象赋引用的时候,就得做一些额外的操作
- 指的是在RSet中做一些额外的记录(在GC中被称为写屏障)
- 这个写屏障不等于内存屏障
-
阿里的多租户JVM
- 每租户单空间
- session based GC
-
每个Region有多大
-
新老年代比例 5%-60%
- 一般不用手工指定
- 因为这是G1预测STW停顿时间的基准
-
humongous object(大对象)
对象超过单个region的50% 或者 跨越多个region
G1中的MixedGC
-XX:InitiatingHeapOccupancyPercent 老年代占用空间达到整堆内存阈值
- 默认值45%
- 当old对象超过这个值,启动MixedGC
MixedGC过程
- 初始标记 STW
- 并发标记
- 最终标记 STW(重新标记)
- 筛选回收 STW(并行)
三色标记法
并发标记算法,在G1和CMS中使用
- 白色:未被标记的对象
- 灰色:自身被标记,成员变量未被标记
- 黑色:自身和成员变量均已标记完成
漏标:B->D断开,A->D
产生漏标需要同时满足两个条件:
- 标记进行时增加了一个黑到白的引用,如果不重新对黑色进行处理,则会漏标
- 标记进行时删除了灰色对象到白对象的引用,那么这个白对象有可能被漏标
解决漏标的两种方法:
增量更新 【CMS】
incremental update -- 增量更新 -- 关注引用的增加
把黑色重新标记为灰色,下次重新扫描属性
SATB 【G1】
SATB 【snapshot at the beginning】 -- 关注引用的删除
当B->D消失时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到
为什么G1使用SATB?
灰色->白色引用消失时,如果没有黑色指向白色,引用会被push到堆栈,下次扫描时拿到这个引用, 由于与RSet的存在,不需要扫描整个堆去查找指向白色的引用,效率比较高。
SATB配合RSet
CMS日志分析
执行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.mashibing.jvm.gc.T15_FullGC_Problem01
[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
ParNew:年轻代收集器
6144->640:收集前后的对比
(6144):整个年轻代容量
6585 -> 2770:整个堆的情况
(19840):整个堆大小
[GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
//8511 (13696) : 老年代使用(最大)
//9866 (19840) : 整个堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
//这里的时间意义不大,因为是并发执行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//标记Card为Dirty,也称为Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//STW阶段,YG occupancy:年轻代占用及容量
//[Rescan (parallel):STW下的存活对象标记
//weak refs processing: 弱引用处理
//class unloading: 卸载用不到的class
//scrub symbol(string) table:
//cleaning up symbol and string tables which hold class-level metadata and
//internalized string respectively
//CMS-remark: 8511K(13696K): 阶段过后的老年代占用及容量
//10108K(19840K): 阶段过后的堆占用及容量
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
//标记已经完成,进行并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//重置内部结构,为下次GC做准备
G1日志详解
[GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
//young -> 年轻代 Evacuation-> 复制存活对象
//initial-mark 混合回收的阶段,这里是YGC混合老年代回收
[Parallel Time: 1.5 ms, GC Workers: 1] //一个GC线程
[GC Worker Start (ms): 92635.7]
[Ext Root Scanning (ms): 1.1]
[Update RS (ms): 0.0]
[Processed Buffers: 1]
[Scan RS (ms): 0.0]
[Code Root Scanning (ms): 0.0]
[Object Copy (ms): 0.1]
[Termination (ms): 0.0]
[Termination Attempts: 1]
[GC Worker Other (ms): 0.0]
[GC Worker Total (ms): 1.2]
[GC Worker End (ms): 92636.9]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.0 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
[Times: user=0.00 sys=0.00, real=0.00 secs]
//以下是混合回收其他阶段
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000078 secs]
[GC concurrent-mark-start]
//无法evacuation,进行FGC
[Full GC (Allocation Failure) 18M->18M(20M), 0.0719656 secs]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]