乐趣区

关于java:g1回收器

-XX:+UseG1GC
-XX:InitiatingHeapOccupancyPercent= N 这个参数,默认状况下该参数是 45
-XX:G1MixedGCCountTarget= N 参数能够管制每个混合式周期中回收的 Old 分区数量,该参数的默认值是 8;
-XX:G1HeapRegionSize=N;只有对象大小 >=1/2 region,那么这个对象就会被 JVM 标记为 Humongous object。每一个巨型对象是一组间断的 region,调配在老年代。如:如果 region 为 1m,对象大小为 600KB,那么残余的空间(1024kb – 600kb)将成为碎片,不在参加调配。须要防止 Humongou Obj 的产生,应该防止大对象的加载。、-XX:MaxGCPauseMillis=200 – 设置一个指标最大暂停工夫. 这是一个理想化的指标,JVM 会尽可能的实现它
-XX:G1ReservePercent=n, 默认是 10 G1 会预留一部分内存, 制作一个假天花板, 避免 to-sapce exhausted。

yang gc:当年老代空间不够

mixed gc:老年代大小占整个堆大小百分比达到该阈值时,会触发一次 mixed gc.

full gc:
to-sapce exhausted:老区不够了,这个时候会把 young 区所有对象不论死活都转成 old 区对象,而后紧接着一次 full gc。G1 收集器实现了标记阶段,开始启动混合式垃圾收集,筹备要清理老年代分区,然而老年代分区在垃圾收集器开释出足够的空间之前就曾经被耗尽了。这种失败通常意味着混合式垃圾收集须要更迅速得实现垃圾收集,每次新生代垃圾收集须要解决更多的老年代分区。

Evacuation Failure:是指当 G1 无奈在堆空间中申请新的分区时,G1 便会触发担保机制,执行一次 STW 式的、单线程的 Full GC。Full GC 会对整堆做标记革除和压缩,最初将只蕴含纯正的存活对象。参数 -XX:G1ReservePercent(默认 10%)能够保留空间,来应答降职模式下的异常情况

Metadata GC Threshold:元空间不够,也会触发 full gc。

Humongous Allocation:调配巨型对象时在老年代无奈找到足够的间断分区。

Remembered Set:虚拟机发现程序在对 Reference 类型的数据进行写操作时,会产生一个 Write Barrier 临时中断写操作,查看 Reference 援用的对象是否处于不同的 Region 之中。如果是,便通过 Card Table 把相干援用信息记录到被援用对象所属的 Region 的 Remembered Set 之中。RSet 外面记录了援用 – 就是其余 Region 中指向本 Region 中所有对象的所有援用,也就是谁援用了我的对象。

G1 GC 每次都会对年老代进行整体收集(全副扫描)。因而 young->old 和 young->young 也不须要在 RSet 中记录。而对于 old->young 和 old->old 的跨代对象援用,须要领有 RSet。

对于 G1 进行 YGC 时的跨代援用,以及进行 Mixed GC 时的 old 间跨 region 援用,只有到本 Region RSet 所记录的 region 中扫描援用了脏 card 区域的对象,再如法溯源,判断其是否存活存活,进而确定本分区内的对象存活状况。而不须要扫描整个堆了

PLAB(promotion local allocation buffer)。每一个线程在 survival space 和 old space 中都一个 PLAB。在晋升的时候,能够防止多线程的竞争,从而晋升效率。

CSet(收集汇合)代表每次 GC 暂停时回收的一系列指标分区。在任意一次收集暂停中,CSet 所有分区都会被开释,外部存活的对象都会被转移到调配的闲暇分区中。因而无论是年老代收集,还是混合收集,工作的机制都是统一的。年老代收集 CSet 只包容年老代分区,而混合收集会通过启发式算法,在老年代候选回收分区中,筛选出回收收益最高的分区增加到 CSet 中。

候选老年代分区的 CSet 准入条件,能够通过活跃度阈值 -XX:G1MixedGCLiveThresholdPercent(默认 85%)进行设置,从而拦挡那些回收开销微小的对象;同时,每次混合收集能够蕴含候选老年代分区,可依据 CSet 对堆的总大小占比 -XX:G1OldCSetRegionThresholdPercent(默认 10%)设置数量下限。G1 的收集都是依据 CSet 进行操作的,年老代收集与混合收集没有显著的不同,最大的区别在于两种收集的触发条件。

年老代垃圾回收只会回收 Eden 区和 Survivor 区。
YGC 时, 首先 G1 进行应用程序的执行(Stop-The-World),G1 创立回收集(Collection Set), 回收集是指须要被回收的内存分段的汇合, 年老代回收过程的回收集蕴含年老代 Eden 区和 Survivor 区所有的内存分段。

而后开始如下回收过程:

第一阶段, 扫描根。
根是指 static 变量指向的对象, 正在执行的办法调用链条上的局部变量等。跟援用连同 RSet 记录的内部援用作为扫描存活对象的入口。

第二阶段, 更新 RSet。
解决 dirty card queue(见备注)中的 card, 更新 RSet。此阶段实现后,RSet 能够精确的反映老年代对所在的内存分段中对象的援用。
备注:
对于应用程序的援用赋值语句 object.field=object,JVM 会在之前和之后执行非凡的操作以在 dirty card queue 中入队一个保留了对象援用信息的 card。在年老代回收的时候,G1 会对 Dirty Card Queue 中所有的 card 进行解决, 以更新 RSet, 保障 RSet 实时精确的反映援用关系。
那为什么不在援用赋值语句处间接更新 RSet 呢? 这是为了性能的须要,RSet 的解决须要线程同步, 开销会很大, 应用队列性能会好很多

第三阶段, 解决 RSet。
辨认被老年代对象指向的 Eden 中的对象, 这些被指向的 Eden 中的对象被认为是存活的对象。

第四阶段, 复制对象。
此阶段, 对象树被遍历,Eden 区内存段中存活的对象会被复制到 Survivor 区中空的内存分段,Survivor 区内存段中存活的对象如果年龄未达阈值, 年龄会加 1, 达到阈值会被复制到 Old 区中空的内存分段。如果 Survivor 空间不够,Eden 空间的局部数据会间接降职到老年代空间。

第五阶段, 解决援用。
解决 Soft,Weak,Phantom,Final,JNI Weak 等援用。最终 Eden 空间的数据为空,GC 进行工作, 而指标内存中的对象都是间断存储的, 没有碎片, 所以复制过程能够达到内存整理的成果, 缩小碎片。

G1 回收过程二: 并发标记过程

  1. 初始标记阶段: 标记从根节点间接可达的对象。这个阶段是 STW 的, 并且会触发一次年老代 GC。
  2. 根区域扫描(Root Region Scanning): G1 GC 扫描 survivor 区间接可达的老年代区域对象, 并标记被援用的对象。这一过程必须在 young GC 之前实现。
  3. 并发标记(Concurrent Marking): 在整个堆中进行并发标记(和应用程序并发执行), 此过程可能被 young GC 中断。在并发标记阶段, 若发现区域对象中的所有对象都是垃圾, 那这个区域会被立刻回收。同时, 并发标记过程中, 会计算每个区域的对象活性(区域中存活对象的比例)。
  4. 再次标记(Remark): 因为应用程序继续进行, 须要修改上一次的标记后果。是 STW 的。G1 中采纳了比 CMS 更快的初始快照法: snapshot-at-the-beginning(SATB)。
  5. 独占清理(cleanup,STW): 计算各个区域的存活对象和 GC 回收比例, 并进行排序, 辨认能够混合回收的区域。为下阶段做铺垫。是 STW 的。
  6. 并发清理阶段: 辨认并清理齐全闲暇的区域。

G1 回收过程三: 混合回收
当越来越多的对象降职到老年代 old region 时, 为了防止堆内存被耗尽, 虚构机会触发一个混合的垃圾收集器, 即 Mixed GC, 该算法并不是一个 Old GC, 除了回收整个 Young Region, 还会回收一部分的 Old Region。这里须要留神: 是一部分老年代, 而不是全副老年代。能够抉择哪些 Old Region 进行收集, 从而能够对垃圾回收的耗时工夫进行管制。也要留神的是 Mixed GC 并不是 Full GC。

并发标记完结当前, 老年代中百分百为垃圾的内存分段被回收了, 局部为垃圾的内存分段被计算了进去。默认状况下, 这些老年代的内存分段会分 8 次 (能够通过 -XX:G1MixedGCCountTarget 设置) 被回收。
混合回收的回收集 (Collection Set) 包含八分之一的老年代内存分段,Eden 区内存分段,Survivor 区内存分段。混合回收的算法和年老代回收的算法齐全一样, 只是回收集多了老年代的内存分段。具体过程请参考下面的年老代回收过程。
因为老年代中的内存分段默认分 8 次回收,G1 会优先回收垃圾多的内存分段。垃圾占内存分段比例越高, 越会被先回收。并且有一个阈值会决定内存分段是否被回收。-XX:G1MixedGCLiveThresholdPercent, 默认为 65%, 意思是垃圾占内存分段比例要达到 65% 才会被回收。如果垃圾占比太低, 意味着存活的对象占比高, 在复制的时候会破费更多的工夫。
混合回收并不一定要进行 8 次。有一个阈值 -XX:G1HeapWastePercent, 默认值为 10%, 意思是容许整个堆内存中有 10% 的空间被节约, 意味着如果发现能够回收的垃圾占堆内存的比例低于 10%, 则不再进行混合回收。因为 GC 会破费很多的工夫然而回收到的内存却很少。

g1 STAB 避免漏标
​能够简略了解为, 当一个灰色对象勾销了对红色对象的援用, 那么这个红色对象被变灰
这样做的毛病就是, 这个红色对象有可能并没有彩色对象去援用它, 然而它还是被变灰了, 就会导致它和它的援用, 原本应该被垃圾回收掉, 然而此次 GC 存活了下来, 就是所谓的浮动垃圾. 其实这样是比拟能够忍耐的, 只是让它多存活了一次 GC 而已, 节约一点点空间, 然而会比增量更新更省工夫.

SATB 也是有副作用的。如果被批改援用的白对象就是要被收集的垃圾,这次的标记会让它躲过 GC,这就是 float garbage。因为 SATB 的做法精度比拟低,所以造成的 float garbage 也会比拟多。

https://www.jianshu.com/p/989…
https://www.jianshu.com/p/ac1…

退出移动版