CMS GC garbage collection

HotSpot (oracle introduction of mainstream support JDK JVM implementation) The main objective of the Concurrent Mark JVM cleanup collector (Concurrent Mark Sweep, CMS collector) is: low application pause times. The goal is very important for most interactive applications, such as web application .CMS GC collector is designed as most of the time can be executed in parallel with the application thread will only pause for a short time (to stop the entire application, the following will use Stop The World (STW) in place).

CMS GC of six processes:

 

1.初始标记:为了收集应用程序的对象引用需要暂停应用程序线程,该阶段完成后,应用程序线程再次启动。
2.并发标记:从第一阶段收集到的对象引用开始,遍历所有其他的对象引用。
3.并发预清理:改变当运行第二阶段时,由应用程序线程产生的对象引用,以更新第二阶段的结果。
4.重标记:由于第三阶段是并发的,对象引用可能会发生进一步改变。因此,应用程序线程会再一次
被暂停以更新这些变化,并且在进行实际的清理之前确保一个正确的对象引用视图。
这一阶段十分重要,因为必须避免收集到仍被引用的对象。
5.并发清理:所有不再被应用的对象将从堆里清除掉。
6.并发重置:收集器做一些收尾的工作,以便下一次GC周期能有一个干净的状态。

其中4个阶段(名字以Concurrent开始的)与实际的应用程序是并发执行的,
而其他2个阶段需要暂停应用程序线程(STW).

Then come and present the process CMS GC triggered by a piece of code.

 

public class GCTest {

    private static final int _10MB = 10 * 1024 * 1024;

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws Exception {
        test();

    }

    /**
     * VM arg: -Xms100m(设置最大堆内存) -Xmx100m(设置初始堆内存) 
     * -Xmn50m(设置新生代大小)
     * -XX:+PrintGCDetails(打印GC日志详细信息) 
     * -XX:+UseConcMarkSweepGC (采用 cms gc算法)
     * -XX:+UseParNewGC (新生代采用并行GC方式,
     * 高版本的jdk使用了UseConcMarkSweepGC参数时 这个参数会自动开启)
     * -XX:SurvivorRatio=8 (新生代eden区与survivor区空间比例8:1,
     * eden:fromsurvivor:tosurvivor -->8:1:1)
     * -XX:MaxTenuringThreshold=1 (用于控制对象能经历多少次
     * Minor GC(young gc)才晋升到老年代,默认15次)
     * -XX:+PrintTenuringDistribution(输出survivor区幸存对象的年龄分布)
     * -XX:CMSInitiatingOccupancyFraction=68 *(设置老年代空间使用率多少时触发第一次cms *gc,默认68%)
     * @throws InterruptedException
     */
    public static void test() throws InterruptedException {
        List<byte[]> list = new ArrayList<>();
        for (int n = 1; n < 8; n++) {
            byte[] alloc = new byte[_10MB];
            list.add(alloc);
        }
        Thread.sleep(Integer.MAX_VALUE);

    }

}

Execution show

 

D:\platform\svn\demo>java -Xms100m -Xmx100m -Xmn50m -XX:+PrintGCDetails 
-XX:+UseConcMarkSweepGC -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 
-XX:+PrintTenuringDistribution GCTest
[GC (Allocation Failure) 
[ParNew Desired survivor size 2621440 bytes, new threshold 1 (max 1)
- age   1:     636784 bytes,     636784 total: 33997K->632K(46080K), 0.0105313 secs] 
33997K->31354K(97280K), 0.0107013 secs]
[Times: user=0.01 sys=0.00, real=0.01 secs]
//step 1,young gc,新生代没有空间存入新对象,则发生young gc(也叫 minor gc),
//33997K->632K(46080K), 0.0105313 secs]新生代由33997K gc后变成了632K,
//整个heap区情况: 33997K->31354K(97280K)
//新生代的对象copy(新生代采用的是复制算法收集内存)到survivor区,
//但此处survivor容纳不下,则直接copy到了老年代中大小(可以设置多大的对象直接升级到老年代中,
//参数XX:PretenureSizeThreshold=<value>)
[GC (Allocation Failure) [ParNew: 32961K->32961K(46080K), 0.0001067 secs]
[CMS: 30722K->40960K(51200K), 0.0111639 secs] 63683K->62060K(97280K), 
[Metaspace: 2509K->2509K(1056768K)], 0.0118014 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
//step 2,老年代空间占用大小占比达到阈值,触发第一次老年代GC,即CMS GC
//CMS: 30722K->40960K(51200K): 老年代由30722K变为40960K,总大小51200K
[GC (CMS Initial Mark) [1 CMS-initial-mark: 40960K(51200K)] 72995K(97280K), 0.0004270 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//step 3 初始标记
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//step 4 并发标记
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//step 5 并发预清理
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (CMS Final Remark) [YG occupancy: 32035 K (46080 K)][Rescan (parallel) , 0.0003930 secs]
//step 6重标记 
[weak refs processing, 0.0000436 secs][class unloading, 0.0001861 secs]
[scrub symbol table, 0.0003188 secs]
[scrub string table, 0.0000946 secs]
//weak refs processing 处理old区的弱引用,用于回收native memory
class unloading 回收SystemDictionary
[1 CMS-remark:40960K(51200K)] 72995K(97280K), 0.0013492 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//step 7 并发清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//step 8 并发重置
Heap
 par new generation   total 46080K, used 32445K [0x00000000f9c00000, 0x00000000fce00000, 0x00000000fce00000)
  eden space 40960K,  79% used [0x00000000f9c00000, 0x00000000fbbaf5b0, 0x00000000fc400000)
  from space 5120K,   0% used [0x00000000fc900000, 0x00000000fc900000, 0x00000000fce00000)
  to   space 5120K,   0% used [0x00000000fc400000, 0x00000000fc400000, 0x00000000fc900000)
 concurrent mark-sweep generation total 51200K, used 40960K [0x00000000fce00000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 2515K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 269K, capacity 386K, committed 512K, reserved 1048576K

Corresponding comments are marked in detail, what is now GC log interpretation:
basically this format: the size of the occupied area before recovery -> recovered area occupied by the size (the size of the region set), time-consuming.
Take this now step2 part of the log to do a comprehensive analysis of a typical log interpretation GC:

 

[GC (Allocation Failure) [ParNew: 32961K->32961K(46080K), 0.0001067 secs]
[CMS: 30722K->40960K(51200K), 0.0111639 secs] 63683K->62060K(97280K), 
[Metaspace: 2509K->2509K(1056768K)], 0.0118014 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]

 

[ParNew: 32961K->32961K(46080K), 0.0001067 secs]

ParNew shows that the new generation is carried out in parallel GC,

 

串行收集器:
DefNew:是使用-XX:+UseSerialGC(新生代,老年代都使用串行回收收集器)。
并行收集器:
ParNew:是使用-XX:+UseParNewGC(新生代使用并行收集器,老年代使用串行回收收集器)或者-XX:+UseConcMarkSweepGC(新生代使用并行收集器,老年代使用CMS)。
PSYoungGen:是使用-XX:+UseParallelOldGC(新生代,老年代都使用并行回收收集器)或者-XX:+UseParallelGC(新生代使用并行回收收集器,老年代使用串行收集器)
garbage-first heap:是使用-XX:+UseG1GC(G1收集器)

32961K-> 32961K (46080K) by the size of the new generation into 32961K 32961K, the total size of 46080K, young gc consuming 0.0001067 secs.

 

[CMS: 30722K->40960K(51200K), 0.0111639 secs]

CMS: is the show's old heap (because only act on the old CMS's),

 

 63683K->62060K(97280K)

heap area case,

 

[Metaspace: 2509K->2509K(1056768K)]

Metaspace: jdk new feature space element 8, can be easily understood to permanently replace previous generations PermGen Space 8 (area method).
The method of the JVM specification region, is permanently substituting an implementation of the JVM specification, meta a spatial region is also a method of implementation.

 

[Times: user=0.02 sys=0.00, real=0.02 secs]

The implication of the same time user, sys, real time with the linux command output, representing CPU time consumed by the user too, kernel mode CPU time consumed, and the operation from start to finish elapsed wall clock time --- quote from <-depth understanding of the Java virtual machine> 3.5.8 understanding GC logs.

In fact here the whole process is almost complete, but I'm in the implementation process, also I found an interesting thing that is concurrent mode failure, when I was a new object exceeds the maximum memory heap memory after OOM happens when it occurs concurrent mode failure, GC log is as follows:

 

[GC [ParNew: 31539K->496K(46080K), 0.0137601 secs] 31539K->31218K(97280K), 0.0152885 secs] 
[Times: user=0.02 sys=0.00, real=0.02 secs]
[GC [ParNew: 33275K->33275K(46080K), 0.0003866 secs][CMS: 30722K->40960K(51200K), 0.0217084 secs]
63997K->61912K(97280K), [CMS Perm : 2534K->2532K(21248K)], 0.0231226 secs] 
[Times: user=0.02 sys=0.00, real=0.02 secs]
[GC [1 CMS-initial-mark: 40960K(51200K)] 72152K(97280K), 0.0004554 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [CMS[CMS-concurrent-mark: 0.010/0.011 secs] 
[Times: user=0.00 sys=0.00, real=0.01 secs]
 (concurrent mode failure): 40960K->40960K(51200K), 0.0159043 secs] 72152K->72152K(97280K), [CMS Perm : 2532K->2532K(21248K)], 0.0165056 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
[Full GC [CMS: 40960K->40960K(51200K), 0.0075621 secs] 
72152K->72138K(97280K), [CMS Perm : 2532K->2532K(21248K)], 0.0084089 secs]
[Times: user=0.00 sys=0.00, real=0.01 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at GCTest.test(GCTest.java:19)
        at GCTest.main(GCTest.java:12)

The reasons for this are: in the course of the implementation of CMS GC in the same time there are objects to be placed in the old generation, but this time due to lack of space years old.
The same situation also promotion failed this situation, which is due during Minor GC (young gc), survivor space does not fit, subject only into the old era, at a time when the old year also fit caused.

End

Java 9 came out for some time, the default is the gc algorithm Java9 G1 algorithm

Published 15 original articles · won praise 2 · Views 4388

Guess you like

Origin blog.csdn.net/u012632105/article/details/104343323