延着上一次【https://www.cnblogs.com/webor2006/p/11147893.html】的理论继续。
SATB:
- 在G1中,使用的是SATB(Snapshot-At-The-Beginning)的方式,删除的时候记录所有的对象。
- 它有3个步骤【重要!】:
1、在开始标记的时候生成一个快照图,标记存活对象。
2、在并发标记的时候所有被改变的对象入队(在write barrier【写屏障】里把所有旧的引用所指向的对象都变成非白的)。
这样的话对于之前用三色标记可能出错的这个白色对象就会变成灰色的,如下:
就可以避免C正常的不被回收了。
3、可能存在浮动垃圾,将在下次被收集。
G1混合式回收:
- G1到现在可以知道哪些老的分区可加收垃圾最多。当全局并发标记完成后,在某个时刻,就开始了Mixed GC。这些垃圾回收被称作“混合式”是因为他们不仅仅进行正常的新生代垃圾收集,同时也回收部分后台扫描线程标记的分区。
- 混合式GC也是采用的复制清理策略,当GC完成后,会重新释放空间。
G1分代算法:
- 为老年代设置分区的目的是老年代里有的分区垃圾多,有的分区垃圾少,这样在回收的时候可以专注于收集垃圾多的分区,这也是G1名称的由来。
- 不过这个算法并不适合新生代垃圾收集,因为新生代的垃圾收集算法是复制算法,但是新生代也使用了分区机制主要是因为便于代大小的调整。
SATB详解:
- SATB是维持并发GC的一种手段。G1并发的基础就是SATB。SATB可以理解成在GC开始之前对堆内存里的对象做一次快照,此时活的对像就认为是活的,从而开成一个对象图。
- 在GC收集的时候,新生代的对象也认为是活的对象,除此之外其他不可达的对象都认为是垃圾对象。
- 如何找到在GC过程中分配的对象呢?每个region记录着两个top-at-mark-start(TAMS)指针,分别为prevTAMS和nextTAMS。在TAMS以上的对象就是新分配的,因而被视为隐式marked。
- 通过这种方式我们就找到了在GC过程中新分配的对象,并把这些对象认为是活的对象。
- 解决了对象在GC过程中分配的问题,那么在GC过程中引用发生变化的问题怎么解决呢?
- G1给出的解决办法是通过Write Barrier。Write Barrier就是对引用字段进行赋值做了额外处理。通过Write Barrier就可以了解到哪些引用对象发生了什么样的变化。
- mark的过程就是遍历heap标记live object的过程,采用的是三色标记算法,这三种颜色为white(表示还未访问到)、gray(访问到但是它用到的引用还没有完全扫描)、back(访问到而且其用到的引用已经完全扫描完)。
- 整个三色标记算法就是从GC roots出发遍历heap,针对可达对象先标记white为gray,然后再标记gray为black;遍历完成之后所有可达对象都是balck的,所有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对象漏标记。