G1的SATB

Posted 修心而结网

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了G1的SATB相关的知识,希望对你有一定的参考价值。

what:

  SATB全称Snapshot-At-The-Beginning,字面意思是:GC开始时活着对象的一个快照。它是通过root tracing得到的,作用是保持并发GC的正确性。

  具体如何确保并发GC正确性?三色标记法(和CMS的一样)。

 

why:

  三色标记法,是会产生漏标问题。具体是:白色对象接到黑色对象上,并且所有灰色对象到白色对象的引用全部丢失。

 

how:

  在GC开始时,先创建一个对象快照。快照中所有当时活的对象在并发标记时,都认为是活得的,并且并发标记过程中的所有新建的对象都认为是活的。

  SATB有2个重要的Bitmap,分别是:prevBitmap和nextBitmap。2个Bitmap存储在每个region中,并且还配合有2个重要的变量,分别是:preTAMS(pre-top-at-mark-start,代表本region上次完成标记的位置)和nextTAMS(next-top-at-mark-start,随着标记不断向后移动,开始在top位置)。SATB通过控制这两个变量来进行 标记,具体规则如下:

  a、假设第n轮标记开始,将该region的top指针赋值给nextTAMS。在并发标记期间,所有分配的对象都会存在在[nextTAMS,top],SATB可以确保所有对象都是活的;

  b、并发标记结束时,将nextTAMS赋值给preTAMS,SATB会给[bottom,preTAMS]创建一个快照Bitmap,则所有的垃圾对象都可以通过该bitmap找到;

  c、第n+1轮并发标记,和第n轮一样;

         

 

  A阶段,初始标记阶段,通过STW,将region的top赋值给nextTAMS;

  A-B阶段,并发标记阶段;

  B阶段,是并发标记结束阶段。并发标记阶段生成的新对象都会放在[nextTAMS,top]之间,这边对象被定义为“隐式对象”,同时nextBitmap也记录了bottom到nextTAMS之间标记对象的地址;

  C阶段,是垃圾清理阶段。会交换prevBitmap和nextBitmap,同时清理[bottom, preTAMS]之间标记后的垃圾,对应的“隐式对象”,在下个阶段才会被标记清理。

 

2020-10-03:java中satb和tlab有什么区别?

福哥答案2020-10-03:#福大大架构师每日一题#

简单回答:
satb: snapshot-at-the-beginning,快照。
tlab:thread local allocation buffer,线程本地分配缓冲。

中级回答:
satb: snapshot-at-the-beginning,快照。
mark的过程就是遍历heap标记live object,采用的是三色标记算法,这三种颜色为white(表示还未访问到)、gray(访问到但是它用到的引用还没有完全扫描)、black(访问到而且其用到的引用已经完全扫描完),整个三色标记算法就是从GC roots出发遍历heap,针对可达对象先标记white为gray,然后再标记gray为black;遍历完成之后所有可达对象都是black的,所有white都是可以回收的。
SATB仅仅对于在marking开始阶段进行"snapshot"(marked all reachable at mark start),但是concurrent的时候并发修改可能造成对象漏标记,比如
①.对black新引用了一个white对象,然后又从gray对象中删除了对该white对象的引用,这样会造成了该white对象漏标记。
②.对black新引用了一个white对象,然后从gray对象删了一个引用该white对象的white对象,这样也会造成了该white对象漏标记。
③.对black新引用了一个刚new出来的white对象,没有其他gray对象引用该white对象,这样也会造成了该white对象漏标记。
对于三色算法在concurrent的时候可能产生的漏标记问题,SATB在marking阶段中,对于从gray对象移除的目标引用对象标记为gray,对于black引用的新产生的对象标记为black;由于是在开始的时候进行snapshot,因而可能存在Floating Garbage。

tlab:thread local allocation buffer,线程本地分配缓冲。
把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在 Java 堆中预先分配一小块私有内存,也就是本地线程分配缓冲(Thread LocalAllocationBuffer,TLAB),JVM 在线程初始化时,同时也会申请一块指定大小的内存,只给当前线程使用,这样每个线程都单独拥有一个 Buffer,如果 需要分配内存,就在自己的 Buffer 上分配,这样就不存在竞争的情况,可以大大提升分配效率,当 Buffer 容量不够的时候,再重新从 Eden 区域申请一块 继续使用。
TLAB 的目的是在为新对象分配内存空间时,让每个 Java 应用线程能在使用自己专属的分配指针来分配空间,减少同步开销。
TLAB 只是让每个线程有私有的分配指针,但底下存对象的内存空间还是给所有线程访问的,只是其它线程无法在这个区域分配而已。当一个 TLAB 用满(分 配指针 top 撞上分配极限 end 了),就新申请一个 TLAB。
***
[评论](https://user.qzone.qq.com/3182319461/blog/1601680599)















以上是关于G1的SATB的主要内容,如果未能解决你的问题,请参考以下文章

三色算法和SATB算法

最全面的JVM G1学习笔记

G1收集器

CMS 和G1 的区别

在 G1 中将 G1HeapWastePercent 设置为零的后果

深入理解Java虚拟机——G1收集器