-XX:NewRatio=1 | 表示新生代占 |
-XX:SurvivorRatio=8 | 表示Eden:Survivor=8:1 |
-Xms20m | 表示堆空间初始大小为 20 M |
-Xmx20m | 表示堆空间最大大小为 20 M |
-Xmn10m | 表示新生代大小为 10M |
-XX:+UseParNewGC | 表示年轻代使用serial的多线程版本,它是server模式下首选的新生代收集器,因为能与cms配合(我们生产也是这么配的) |
-XX:+UseConcMarkSweepGC | 表示老年代用cms收集器(我们生产也是这么配置的) |
-XX:+PrintGC | 简单打印gc日志 |
-XX:+PrintGCDetails | 详细打印gc日志 |
测试代码
我们两次分配了 4M 的内存空间,人为制造 GC。
/**
* @author 陈树义
* @date 2018.09.29
*/
public class GCDemo {
public static void main(String[] args) {
// allocate 4M space
byte[] b = new byte[4 * 1024 * 1024];
System.out.println("first allocate");
// allocate 4M space
b = new byte[4 * 1024 * 1024];
System.out.println("second allocate");
}
}
打印gc日志
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-Xms20M -Xmx20M -Xmn10M
-XX:NewRatio=1
-XX:+PrintGC
年轻代用ParNew,老年代用cms,初始堆大小20M,最大堆大小20M,年轻代10M,老年代:年轻代=1:1,详细打印gc日志
Connected to the target VM, address: '127.0.0.1:51295', transport: 'socket'
Process finished with exit code 0 |
Young GC部分
- GC:区别MinorGC和FullGC的标识,这次代表的是MinorGC
- Allocation Failure:MinorGC的原因,在这个case里边,由于年轻代不满足申请的空间,因此触发了MinorGC
- ParNew: 8174K->766K(9216K), 0.0007652 secs:经过ParNew收集器的收集,收集前8174K,收集后766K,年轻代大小为9126K,耗时0.0007652秒
- 8174K->766K(19456K), 0.0011366 secs:经过ParNew收集器的收集,收集前8174K,收集后766K,整个堆的大小为19456K,耗时0.0011366秒
FULL GC部分
CMS Initial Mark(阶段1):cms的初始标记,需要stop the world。收集所有GC root 和 被年轻代存活对象直接引用的老年代对象。
CMS-initial-mark: 6598K(10240K):当前老年代被使用了6598K,老年代大小为10240K
11038K(19456K):当前整个堆被使用了11038K,整个堆的大小为19456K
Concurrent Mark(阶段2) :并发标记。会从找到的GC Root开始,找到老年代中存活的对象。并不是老年代中所有存活的对象都会被标记,必须得从GC root出发的才能被标记。不会stop the world。
Concurrent Preclean
这个阶段又是一个并发阶段,和应用线程并行运行,不会中断他们。前一个阶段在并行运行的时候,一些对象的引用已经发生了变化,当这些引用发生变化的时候,JVM会标记堆的这个区域为Dirty Card(包含被标记但是改变了的对象,被认为"dirty"),这就是 Card Marking。那些能够从dirty card对象到达的对象也会被标记,这个标记做完之后,dirty card标记就会被清除了。
Concurrent Abortable Preclean
Final Remark
这个阶段是CMS中第二个并且是最后一个STW的阶段。该阶段的任务是完成标记整个年老代的所有的存活对象。由于之前的预处理是并发的,它可能跟不上应用程序改变的速度,这个时候,STW是非常需要的来完成这个严酷考验的阶段。
通常CMS尽量运行Final Remark阶段在年轻代是足够干净的时候,目的是消除紧接着的连续的几个STW阶段。
1
1
1
1
1
1
1
1