"Three-color marking algorithm" for jvm garbage collection

The three-color marking method is a garbage collection method, which can prevent the JVM from occurring or only occur STW (Stop The World) for a short time, so as to achieve the purpose of clearing the JVM memory garbage. The garbage collection algorithm used by the CMS and G1 garbage collectors in the JVM is the three-color marking method.

Three-color marking algorithm idea

The three-color notation method divides the color of the object into three colors: black, gray, and white.

White : The object has not been marked. (object garbage)

Gray : The object has been marked, but the attributes under the object have not been marked. (GC needs to find garbage from this object)

Black : The object has been marked, and all the attributes under the object have been marked. (object required by the program)

Algorithm process

Starting from the root object of our main method (called GC Root in JVM ), search down along their objects, and use black and white rules to mark all objects connected to GC Root . After scanning, it is generally necessary to perform A short STW (Stop The World), scan again, because the properties of the black object have also been marked, so just find the gray object and continue to mark it down (and because most of the marks The work has already happened at the first concurrent time, so the number of gray objects will be very small, and the marking time will be much shorter), at this time the program continues to execute, and the GC thread scans all the memory, and finds out that it is still marked as white after scanning Objects (garbage), cleared.

specific process:

  1. First create three collections: white, gray, and black.

  1. Put all objects into white collection.

  1. Then traverse all objects from the root node (note that there is no recursive traversal here ), and put the traversed objects from the white collection into the gray collection.

  1. Then traverse the gray collection, put the object referenced by the gray object from the white collection into the gray collection, and then put the gray object into the black collection

  1. Repeat 4 until there is no object in gray

  1. Detect object changes through write-barrier, repeat the above operation

  1. Collect all white objects (garbage)

There is a problem with three-color marking

  1. Floating garbage: During the concurrent marking process, if an object that has been marked as black or gray suddenly becomes garbage, it will not be found because it will not rescan the black marked object, then this object is not The white ones will not be cleared, and cannot be found from the GC Root after re-marking , so they become floating garbage. Floating garbage has little impact on the system and can be left for the next GC to process .

  1. Object missing mark problem (needed objects are recycled): During the concurrent marking process, a business thread disconnects an unscanned white object as garbage (delete the reference), and at the same time the black object references the object (increase the reference ) (these two parts can be in no particular order); because the meaning of the black object is that its attributes have been marked, re-marking will not find it from the black object, resulting in the object being needed by the program, but it needs to Recycled by GC, this problem will cause problems in the system, and CMS and G1 , the two recyclers have taken some measures to deal with these problems when using the three-color marking method, CMS handles the addition of references (Increment Update) , G1 processes the deletion of the reference link (SATB).

Solution

In the JVM virtual machine, there are two common garbage collectors that use this algorithm: CMS (Concurrent Mark Sweep) and G1 (Garbage First). In order to solve the problem of missing objects in the three-color marking method, each has its own method:

CMS review

The CMS (Concurrent Mark Sweep) collector is a collector that aims to obtain the shortest recovery pause time. At present, a large part of Java applications are concentrated on the server side of Internet websites or browser-based B/S systems. These applications usually pay more attention to the response speed of services, and hope that the system pause time is as short as possible to bring users Good interactive experience. The CMS collector is very suitable for the needs of this type of application (but due to some problems, few use CMS as the main garbage collector).

From the name (including "Mark Sweep"), it can be seen that the CMS collector is implemented based on the mark-clear algorithm. Its operation process is more complicated than that of the previous collectors. The whole process is divided into four Steps, including: 1) Initial mark (CMS initial mark) 2) Concurrent mark (CMS concurrent mark) 3) Remark (CMS remark) 4) Concurrent clear (CMS concurrent sweep)

The two steps of initial marking and re-marking still require "Stop The World". The initial mark is just to mark the objects that GCRoots can directly relate to, which is very fast;

The concurrent marking phase is the process of traversing the entire object graph starting from the directly associated objects of GC Roots. This process takes a long time but does not need to pause user threads, and can run concurrently with garbage collection threads;

The re-marking phase is to correct the marking records of the part of the object that has been changed due to the continued operation of the user program during the concurrent marking period. The pause time of this phase is usually slightly longer than the initial marking phase, but it is also much longer than the concurrent marking. short period of time;

The last is the concurrent clearing stage, which cleans up and deletes the dead objects judged in the marking stage. Since there is no need to move surviving objects, this stage can also be concurrent with user threads. Since the garbage collector thread can work together with the user thread in the longest concurrent marking and concurrent clearing phase of the entire process, in general, the memory recovery process of the CMS collector is executed concurrently with the user thread of.

CMS Solution: Incremental Updates

When dealing with the problem of missing labels, CMS uses the incremental update (Increment Update) method to do it:

After an unmarked object (white object) is re-referenced, if the object that references it is black, it will turn gray, and let the GC thread continue to mark its attribute object the next time it is marked twice .

But even so, it still has the problem of missing labels:

  • When a gray object is being reclaimed by a GC thread, when its marked attribute points to a white object (garbage)

  • And the attribute object of this object itself has not been completely marked, it is gray and unchanged

  • After the GC thread marks the last attribute, it thinks that all the attributes have been marked, and marks the gray object as black. The re-referenced white object cannot be marked.

Two other fatal flaws of CMS

  1. CMS adopts the Mark-Sweep algorithm, which will eventually generate a lot of memory fragments. When a certain amount is reached, CMS cannot clean up these fragments. CMS will let the Serial Old garbage processor clean up these garbage fragments, and the Serial Old garbage processor is a single The efficiency of thread operation to clean up garbage is very low. Therefore, when using CMS, there will be a situation where the hardware is upgraded, but it becomes more and more stuck. The reason is that the efficiency of Serial Old GC is too low.

  • Solution: Use the Mark-Sweep-Compact algorithm to reduce garbage debris

  • Tuning parameters (supported use):

-XX:+UseCMSCompactAtFullCollection Turn on CMS compression

-XX:CMSFullGCsBeforeCompaction defaults to 0, which refers to how many times CMS FullGC passes before compression

  1. When the JVM thinks that the memory is not enough, and then use the CMS to clean up the memory concurrently, an OOM problem may occur, and it has to perform Serial Old GC . Serial Old is a single-threaded garbage collection, which is inefficient

  • Solution: Lower the threshold for triggering CMS GC , so that floating garbage will not easily occupy the old age

  • Tuning parameters:

-XX:CMSInitiatingOccupancyFraction 92% can reduce this value, so that the old age occupancy rate reaches this value and the CMS GC is performed

G1 review

G1 (Garbage First) physical memory is no longer divided into generations, but is composed of Regions one by one , but the logical generation still exists. G1 no longer adheres to the fixed size and fixed number of generational area divisions, but divides the continuous Java heap into multiple independent areas (Regions) of equal size. Each Region can act as the Eden space of the new generation, Survivor space, or old age space. The collector can adopt different strategies to deal with Regions that play different roles, so that whether it is a newly created object or an old object that has survived for a period of time and survived multiple collections, it can obtain good collection results.

There is also a special Humongous area in Region, which is specially used to store large objects. G1 believes that as long as the size exceeds half of the capacity of a Region, it can be judged as a large object. The size of each Region can be set by the parameter -XX:G1HeapRegionSize , the value range is 1MB to 32MB, and it should be the Nth power of 2. For those super large objects that exceed the capacity of the entire Region, they will be stored in N consecutive Humongous Regions. Most of the behaviors of G1 regard the Humongous Region as part of the old age, as shown in the figure

G1 pre-knowledge

Card Table (available in various garbage collectors)

  • 由于在进行YoungGC时,我们在进行对一个对象是否被引用的过程,需要扫描整个Old区,所以JVM设计了CardTable,将Old区分为一个一个Card,一个Card有多个对象;如果一个Card中的对象有引用指向Young区,则将其标记为Dirty Card,下次需要进行YoungGC时,只需要去扫描Dirty Card即可。

  • Card Table 在底层数据结构以 Bit Map实现。

RSet(Remembered Set)

是辅助GC过程的一种结构,典型的空间换时间工具,和Card Table有些类似。

后面说到的CSet(Collection Set)也是辅助GC的,它记录了GC要收集的Region集合,集合里的Region可以是任意年代的。

在GC的时候,对于old->young和old->old的跨代对象引用,只要扫描对应的CSet中的RSet即可。逻辑上说每个Region都有一个RSet,RSet记录了其他Region中的对象引用本Region中对象的关系,属于points-into结构(谁引用了我的对象)。

而Card Table则是一种points-out(我引用了谁的对象)的结构,每个Card 覆盖一定范围的Heap(一般为512Bytes)。G1的RSet是在Card Table的基础上实现的:每个Region会记录下别的Region有指向自己的指针,并标记这些指针分别在哪些Card的范围内。这个RSet其实是一个Hash Table,Key是别的Region的起始地址,Value是一个集合,里面的元素是Card Table的Index。每个Region中都有一个RSet,记录其他Region到本Region的引用信息;使得垃圾回收器不需要扫描整个堆找到谁引用当前分区中的对象,只需要扫描RSet即可。

CSet(Collection Set)

一组可被回收的分区Region的集合, 是多个对象的集合内存区域。

新生代与老年代的比例

5% - 60%,一般不使用手工指定,因为这是G1预测停顿时间的基准,这地方简要说明一下,G1可以指定一个预期的停顿时间,然后G1会根据你设定的时间来动态调整年轻代的比例,例如时间长,就将年轻代比例调小,让YGC尽早行。

G1解决办法:SATB

SATB(Snapshot At The Beginning), 在应对漏标问题时,G1使用了SATB方法来做,具体流程:

  1. 在开始标记的时候生成一个快照图标记存活对象

  1. 在一个引用断开后,要将此引用推到GC的堆栈里,保证白色对象(垃圾)还能被GC线程扫描到(在write barrier(写屏障)里把所有旧的引用所指向的对象都变成非白的)。

  1. 配合Rset,去扫描哪些Region引用到当前的白色对象,若没有引用到当前对象,则回收

SATB详细流程

  1. SATB是维持并发GC的一种手段。G1并发的基础就是SATB。SATB可以理解成在GC开始之前对堆内存里的对象做一次快照,此时活的对像就认为是活的,从而开成一个对象图。

  1. 在GC收集的时候,新生代的对象也认为是活的对象,除此之外其他不可达的对象都认为是垃圾对象。

  1. 如何找到在GC过程中分配的对象呢?每个region记录着两个top-at-mark-start(TAMS)指针,分别为prevTAMS和nextTAMS。在TAMS以上的对象就是新分配的,因而被视为隐式marked。

  1. 通过这种方式我们就找到了在GC过程中新分配的对象,并把这些对象认为是活的对象。

  1. 解决了对象在GC过程中分配的问题,那么在GC过程中引用发生变化的问题怎么解决呢?

  1. G1给出的解决办法是通过Write Barrier。Write Barrier就是对引用字段进行赋值做了额外处理。通过Write Barrier就可以了解到哪些引用对象发生了什么样的变化。

  1. mark的过程就是遍历heap标记live object的过程,采用的是三色标记算法,这三种颜色为white(表示还未访问到)、gray(访问到但是它用到的引用还没有完全扫描)、back(访问到而且其用到的引用已经完全扫描完)。

  1. 整个三色标记算法就是从GC roots出发遍历heap,针对可达对象先标记white为gray,然后再标记gray为black;遍历完成之后所有可达对象都是balck的,所有white都是可以回收的。

  1. SATB仅仅对于在marking开始阶段进行“snapshot”(marked all reachable at mark start),但是concurrent的时候并发修改可能造成对象漏标记。

  1. 对black新引用了一个white对象,然后又从gray对象中删除了对该white对象的引用,这样会造成了该white对象漏标记。

  1. 对black新引用了一个white对象,然后从gray对象删了一个引用该white对象的white对象,这样也会造成了该white对象漏标记。

  1. 对black新引用了一个刚new出来的white对象,没有其他gray对象引用该white对象,这样也会造成了该white对象漏标记。

SATB效率高于增量更新的原因?

因为SATB在重新标记环节只需要去重新扫描那些被推到堆栈中的引用,并配合Rset来判断当前对象是否被引用来进行回收;

并且在最后G1并不会选择回收所有垃圾对象,而是根据Region的垃圾多少来判断与预估回收价值(指回收的垃圾与回收的STW时间的一个预估值),将一个或者多个Region放到CSet中,最后将这些Region中的存活对象压缩并复制到新的Region中,清空原来的Region

G1会不会进行Full GC?

会,当内存满了的时候就会进行Full GC;且JDK10之前的Full GC,为单线程的,所以使用G1需要避免Full GC的产生。

解决方案:

  • 加大内存;

  • 提高CPU性能,加快GC回收速度,而对象增加速度赶不上回收速度,则Full GC可以避免;

  • 降低进行Mixed GC触发的阈值,让Mixed GC提早发生(默认45%)

Guess you like

Origin blog.csdn.net/qq_31671187/article/details/128799708