# GC日志专题
所有对象的创建,生命周期中的使用,到最后销毁的整个过程,都是由GC模块管理的,真正应该称之为内存管理器。
# GC日志打印常用参数
打印GC日志:
java -XX:+PrintGCDetails xxxclass 执行时,会打印gc的详细日志
-XX:+PrintGCDateStamps 日志会打印时间戳
-Xloggc:gc.demo.log 将gc日志输出到指定文件gc.demo.log
# 解析GC日志
下面会使用同一段程序,切换多个GC,来解析GC日志
执行的代码:
/*
演示GC日志生成与解读
*/
public class GCLogAnalysis {
private static Random random = new Random();
public static void main(String[] args) {
// 当前毫秒时间戳
long startMillis = System.currentTimeMillis();
// 持续运行毫秒数; 可根据需要进行修改
long timeoutMillis = TimeUnit.SECONDS.toMillis(1);
// 结束时间戳
long endMillis = startMillis + timeoutMillis;
LongAdder counter = new LongAdder();
System.out.println("正在执行...");
// 缓存一部分对象; 进入老年代
int cacheSize = 2000;
Object[] cachedGarbage = new Object[cacheSize];
// 在此时间范围内,持续循环
while (System.currentTimeMillis() < endMillis) {
// 生成垃圾对象
Object garbage = generateGarbage(100*1024);
counter.increment();
int randomIndex = random.nextInt(2 * cacheSize);
if (randomIndex < cacheSize) {
cachedGarbage[randomIndex] = garbage;
}
}
System.out.println("执行结束!共生成对象次数:" + counter.longValue());
}
// 生成对象
private static Object generateGarbage(int max) {
int randomSize = random.nextInt(max);
int type = randomSize % 4;
Object result = null;
switch (type) {
case 0:
result = new int[randomSize];
break;
case 1:
result = new byte[randomSize];
break;
case 2:
result = new double[randomSize];
break;
default:
StringBuilder builder = new StringBuilder();
String randomString = "randomString-Anything";
while (builder.length() < randomSize) {
builder.append(randomString);
builder.append(max);
builder.append(randomSize);
}
result = builder.toString();
break;
}
return result;
}
}
# 并行GC
Java8默认的GC
下面是产生YoungGC时的日志示例:
jesse$ java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xmx2g -Xms2g javaclass
2021-05-15T15:57:00.829+0800: [GC (Allocation Failure) [PSYoungGen: 524800K->87022K(611840K)] 524800K->153159K(2010112K), 0.0405788 secs] [Times: user=0.19 sys=0.12, real=0.04 secs]
2021-05-15T15:57:00.971+0800: [GC (Allocation Failure) [PSYoungGen: 611822K->87024K(611840K)] 677959K->266402K(2010112K), 0.0534516 secs] [Times: user=0.23 sys=0.20, real=0.05 secs]
2021-05-15T15:57:01.120+0800: [GC (Allocation Failure) [PSYoungGen: 611495K->87035K(611840K)] 790873K->382782K(2010112K), 0.0576040 secs] [Times: user=0.36 sys=0.09, real=0.06 secs]
2021-05-15T15:57:01.270+0800: [GC (Allocation Failure) [PSYoungGen: 611835K->87027K(611840K)] 907582K->497519K(2010112K), 0.0584238 secs] [Times: user=0.36 sys=0.11, real=0.06 secs]
2021-05-15T15:57:01.421+0800: [GC (Allocation Failure) [PSYoungGen: 611827K->87029K(611840K)] 1022319K->621339K(2010112K), 0.0617433 secs] [Times: user=0.34 sys=0.15, real=0.06 secs]
2021-05-15T15:57:01.577+0800: [GC (Allocation Failure) [PSYoungGen: 611711K->87035K(321024K)] 1146020K->733392K(1719296K), 0.0685264 secs] [Times: user=0.31 sys=0.19, real=0.08 secs]
执行结束!共生成对象次数:11859
Heap
PSYoungGen total 321024K, used 96528K [0x00000000d5580000, 0x0000000100000000, 0x0000000100000000)
eden space 233984K, 4% used [0x00000000d5580000,0x00000000d5ec53c8,0x00000000e3a00000)
from space 87040K, 99% used [0x00000000fab00000,0x00000000ffffeea0,0x0000000100000000)
to space 232448K, 0% used [0x00000000e3a00000,0x00000000e3a00000,0x00000000f1d00000)
ParOldGen total 1398272K, used 646357K [0x0000000080000000, 0x00000000d5580000, 0x00000000d5580000)
object space 1398272K, 46% used [0x0000000080000000,0x00000000a7735530,0x00000000d5580000)
Metaspace used 2546K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 273K, capacity 386K, committed 512K, reserved 1048576K
接下来我们分析下GC日志具体有什么内容:先看日志第一行
| 日志 | 含义 |
|---|---|
| 2021-05-15T15:57:00.829+0800 | 是-XX:+PrintGCDateStamps加上后打印出来的时间戳 |
| GC (Allocation Failure) | 表示gc执行的原因,此处意为分配失败 |
| PSYoungGen: 524800K->87022K(611840K) | PSYoungGen:并行young GC 表示young区占用的内存(对象)从524800K压缩到了87022K,括号里的611840K代表整个young区的最大容量 |
| 524800K->153159K(2010112K) | 后面这段表示整个堆内存的内存占用,这里与上面young区差的就是old区 |
| 0.0405788 secs | YoungGC的时间 |
| [Times: user=0.19 sys=0.12, real=0.04 secs] | youngGC的用户耗时、系统耗时、实际耗时 |
可以看出第一次垃圾回收时young区和整个堆内存的内存占用是一致的,这是因为最开始还没有对象晋升到old区。
图文示例:

下面是FullGC日志:
2021-05-17T23:01:02.587+0800: [Full GC (Ergonomics) [PSYoungGen: 17594K->0K(113664K)] [ParOldGen: 308012K->265261K(341504K)] 325607K->265261K(455168K), [Metaspace: 2540K->2540K(1056768K)], 0.0694247 secs] [Times: user=0.52 sys=0.01, real=0.06 secs]
2021-05-17T23:01:02.668+0800: [GC (Allocation Failure) [PSYoungGen: 56832K->17484K(113664K)] 322093K->282745K(455168K), 0.0064969 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
2021-05-17T23:01:02.685+0800: [GC (Allocation Failure) [PSYoungGen: 74213K->18540K(113664K)] 339474K->300211K(455168K), 0.0120198 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]
2021-05-17T23:01:02.706+0800: [GC (Allocation Failure) [PSYoungGen: 75341K->25265K(113664K)] 357011K->323768K(455168K), 0.0140829 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
2021-05-17T23:01:02.721+0800: [Full GC (Ergonomics) [PSYoungGen: 25265K->0K(113664K)] [ParOldGen: 298502K->282852K(341504K)] 323768K->282852K(455168K), [Metaspace: 2540K->2540K(1056768K)], 0.0725073 secs] [Times: user=0.56 sys=0.00, real=0.07 secs]
分析FullGC日志:第一行
Full GC (Ergonomics)代表执行的是FullGC,Ergonomics的中文意思是人体工程学,也就是根据算法估算下次可能会无法分配内存,提前执行一次FullGC。
出现FullGC的常见原因:
Full GC (Allocation Failure)
Full GC (Ergonomics)
Full GC (Metadata GC Threshold)
在JVM中的垃圾收集器中的Ergonomics就是负责自动的调解gc暂停时间和吞吐量之间的平衡,然后你的虚拟机性能更好的一种做法。
[PSYoungGen: 17594K->0K(113664K)]young区在FullGC时会清空掉。[ParOldGen: 308012K->265261K(341504K)]old区在FullGC时会进行压缩。[Metaspace: 2540K->2540K(1056768K)]元数据区执行FullGC时没有变化,jdk7是PSPermGen(永久代),jdk8更改为meta区(元空间)。0.0694247 secs代表FullGC的耗时[Times: user=0.52 sys=0.01, real=0.06 secs]与youngGC一样。
图文示例:

# 串行GC
jesse$ java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseSerialGC -Xmx100m -Xms100m GCLogAnalysis
2021-05-18T23:47:27.922+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.922+0800: [DefNew: 26896K->3392K(30720K), 0.0044572 secs] 26896K->8430K(99008K), 0.0045628 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2021-05-18T23:47:27.936+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.936+0800: [DefNew: 30443K->3391K(30720K), 0.0076210 secs] 35482K->17402K(99008K), 0.0076747 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
2021-05-18T23:47:27.957+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.957+0800: [DefNew: 30719K->3372K(30720K), 0.0048223 secs] 44730K->25250K(99008K), 0.0048821 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-18T23:47:27.970+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.970+0800: [DefNew: 30700K->3381K(30720K), 0.0050724 secs] 52578K->33409K(99008K), 0.0051447 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2021-05-18T23:47:27.982+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.982+0800: [DefNew: 30709K->3389K(30720K), 0.0073571 secs] 60737K->44768K(99008K), 0.0074114 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-18T23:47:27.996+0800: [GC (Allocation Failure) 2021-05-18T23:47:27.996+0800: [DefNew: 30453K->3391K(30720K), 0.0061754 secs] 71832K->53531K(99008K), 0.0062303 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
2021-05-18T23:47:28.009+0800: [GC (Allocation Failure) 2021-05-18T23:47:28.009+0800: [DefNew: 30550K->3389K(30720K), 0.0062526 secs] 80690K->62820K(99008K), 0.0063055 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-18T23:47:28.020+0800: [GC (Allocation Failure) 2021-05-18T23:47:28.020+0800: [DefNew: 30622K->30622K(30720K), 0.0000235 secs]2021-05-18T23:47:28.020+0800: [Tenured: 59431K->68237K(68288K), 0.0158607 secs] 90053K->71211K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0159623 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2021-05-18T23:47:28.042+0800: [Full GC (Allocation Failure) 2021-05-18T23:47:28.042+0800: [Tenured: 68237K->68246K(68288K), 0.0152800 secs] 98730K->79069K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0153404 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2021-05-18T23:47:28.061+0800: [Full GC (Allocation Failure) 2021-05-18T23:47:28.061+0800: [Tenured: 68246K->67959K(68288K), 0.0149245 secs] 98878K->84519K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0149797 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
可以看出UseSerialGC在young区使用了DefNew垃圾收集器,Tenured则是代表old区,并且在某一次非FullGC时,同时执行了young区和old区的垃圾回收。其他与并行GC区别不大。
# CMS GC
jesse$ java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -Xmx100m -Xms100m GCLogAnalysis
2021-05-19T00:11:15.132+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.132+0800: [ParNew: 27229K->3391K(30720K), 0.0037007 secs] 27229K->10610K(99008K), 0.0037781 secs] [Times: user=0.01 sys=0.02, real=0.00 secs]
-------此处发生多次GC (Allocation Failure)-------
2021-05-19T00:11:15.192+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 41471K(68288K)] 45517K(99008K), 0.0002588 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.193+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.193+0800: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.193+0800: [CMS-concurrent-preclean-start]
2021-05-19T00:11:15.194+0800: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.194+0800: [CMS-concurrent-abortable-preclean-start]
2021-05-19T00:11:15.198+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.198+0800: [ParNew: 30667K->3376K(30720K), 0.0064299 secs] 72138K->54772K(99008K), 0.0064830 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.210+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.210+0800: [ParNew: 30704K->3391K(30720K), 0.0049883 secs] 82100K->62027K(99008K), 0.0050630 secs] [Times: user=0.04 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.221+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.221+0800: [ParNew: 30708K->30708K(30720K), 0.0000506 secs]2021-05-19T00:11:15.221+0800: [CMS2021-05-19T00:11:15.221+0800: [CMS-concurrent-abortable-preclean: 0.001/0.028 secs] [Times: user=0.10 sys=0.00, real=0.03 secs]
(concurrent mode failure): 58635K->65869K(68288K), 0.0192665 secs] 89344K->65869K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0194171 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.247+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.247+0800: [ParNew: 27072K->27072K(30720K), 0.0000383 secs]2021-05-19T00:11:15.247+0800: [CMS: 65869K->68067K(68288K), 0.0169597 secs] 92942K->72852K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0171223 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.264+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68067K(68288K)] 73863K(99008K), 0.0004737 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.264+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.265+0800: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.265+0800: [CMS-concurrent-preclean-start]
2021-05-19T00:11:15.266+0800: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.266+0800: [CMS-concurrent-abortable-preclean-start]
2021-05-19T00:11:15.266+0800: [CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.266+0800: [GC (CMS Final Remark) [YG occupancy: 9697 K (30720 K)]2021-05-19T00:11:15.266+0800: [Rescan (parallel) , 0.0002076 secs]2021-05-19T00:11:15.266+0800: [weak refs processing, 0.0000140 secs]2021-05-19T00:11:15.266+0800: [class unloading, 0.0002604 secs]2021-05-19T00:11:15.266+0800: [scrub symbol table, 0.0003168 secs]2021-05-19T00:11:15.267+0800: [scrub string table, 0.0002255 secs][1 CMS-remark: 68067K(68288K)] 77765K(99008K), 0.0010911 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.267+0800: [CMS-concurrent-sweep-start]
2021-05-19T00:11:15.267+0800: [CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.267+0800: [CMS-concurrent-reset-start]
2021-05-19T00:11:15.267+0800: [CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.271+0800: [GC (Allocation Failure) 2021-05-19T00:11:15.271+0800: [ParNew: 30694K->30694K(30720K), 0.0001260 secs]2021-05-19T00:11:15.271+0800: [CMS: 68067K->68203K(68288K), 0.0138106 secs] 98761K->81654K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0140288 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
----------------此处省略多行类似GC日志----------------
2021-05-19T00:11:15.337+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68117K(68288K)] 92674K(99008K), 0.0006324 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.338+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.338+0800: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.338+0800: [CMS-concurrent-preclean-start]
2021-05-19T00:11:15.339+0800: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.339+0800: [CMS-concurrent-abortable-preclean-start]
2021-05-19T00:11:15.339+0800: [CMS-concurrent-abortable-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.339+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.339+0800: [CMS (concurrent mode failure): 68117K->68261K(68288K), 0.0082180 secs] 98833K->92954K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0082750 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.349+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.349+0800: [CMS: 68261K->68227K(68288K), 0.0194007 secs] 98965K->94020K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0194681 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.368+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68227K(68288K)] 94301K(99008K), 0.0003624 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.369+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.369+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.369+0800: [CMS2021-05-19T00:11:15.371+0800: [CMS-concurrent-mark: 0.001/0.002 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
(concurrent mode failure): 68227K->68281K(68288K), 0.0221579 secs] 98721K->95980K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0222169 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.392+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.392+0800: [CMS: 68281K->68213K(68288K), 0.0216581 secs] 98827K->96411K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0217184 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.414+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68213K(68288K)] 96995K(99008K), 0.0004368 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.415+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.415+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.415+0800: [CMS2021-05-19T00:11:15.417+0800: [CMS-concurrent-mark: 0.001/0.002 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
(concurrent mode failure): 68213K->68198K(68288K), 0.0213393 secs] 98855K->96402K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0214075 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
2021-05-19T00:11:15.437+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.437+0800: [CMS: 68198K->68143K(68288K), 0.0054181 secs] 98795K->97051K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0055051 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.443+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68143K(68288K)] 97426K(99008K), 0.0007019 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.444+0800: [CMS-concurrent-mark-start]
2021-05-19T00:11:15.444+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.444+0800: [CMS2021-05-19T00:11:15.446+0800: [CMS-concurrent-mark: 0.001/0.002 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
(concurrent mode failure): 68143K->68143K(68288K), 0.0032796 secs] 98614K->97544K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0033336 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.448+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.448+0800: [CMS: 68143K->68143K(68288K), 0.0013556 secs] 98839K->98223K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0014120 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.449+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.450+0800: [CMS: 68143K->68143K(68288K), 0.0011270 secs] 98546K->98546K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0011929 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.451+0800: [Full GC (Allocation Failure) 2021-05-19T00:11:15.451+0800: [CMS: 68143K->68125K(68288K), 0.0152224 secs] 98546K->98527K(99008K), [Metaspace: 2540K->2540K(1056768K)], 0.0152626 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.466+0800: [GC (CMS Initial Mark) [1 CMS-initial-mark: 68125K(68288K)] 98527K(99008K), 0.0002910 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2021-05-19T00:11:15.467+0800: [CMS-concurrent-mark-start]
Exception in thread "main" 2021-05-19T00:11:15.467+0800: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
2021-05-19T00:11:15.467+0800: [CMS-concurrent-preclean-start]
java.lang.OutOfMemoryError: Java heap space
at GCLogAnalysis.generateGarbage(GCLogAnalysis.java:42)
at GCLogAnalysis.main(GCLogAnalysis.java:25)
可以看出CMS GC在young区使用的是ParNew垃圾收集器,在老年代就是使用CMS垃圾收集器了,可以发现CMS垃圾收集会执行很多步骤。
# G1 GC
jesse$ java -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+UseG1GC -Xmx100m -Xms100m GCLogAnalysis
2021-05-19T00:45:29.601+0800: [GC pause (G1 Evacuation Pause) (young) 29M->10093K(100M), 0.0032925 secs]
2021-05-19T00:45:29.621+0800: [GC pause (G1 Evacuation Pause) (young) 45M->24M(100M), 0.0048468 secs]
2021-05-19T00:45:29.642+0800: [GC pause (G1 Evacuation Pause) (young)-- 75M->49M(100M), 0.0049933 secs]
2021-05-19T00:45:29.647+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 50M->48M(100M), 0.0021580 secs]
2021-05-19T00:45:29.650+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.650+0800: [GC concurrent-root-region-scan-end, 0.0000263 secs]
2021-05-19T00:45:29.650+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.651+0800: [GC concurrent-mark-end, 0.0012330 secs]
2021-05-19T00:45:29.651+0800: [GC remark, 0.0010260 secs]
2021-05-19T00:45:29.652+0800: [GC cleanup 54M->54M(100M), 0.0003197 secs]
2021-05-19T00:45:29.658+0800: [GC pause (G1 Evacuation Pause) (young)-- 82M->69M(100M), 0.0033098 secs]
2021-05-19T00:45:29.661+0800: [GC pause (G1 Evacuation Pause) (mixed) 70M->63M(100M), 0.0017333 secs]
2021-05-19T00:45:29.665+0800: [GC pause (G1 Evacuation Pause) (young) 75M->67M(100M), 0.0018694 secs]
2021-05-19T00:45:29.667+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 68M->67M(100M), 0.0012085 secs]
2021-05-19T00:45:29.669+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.669+0800: [GC concurrent-root-region-scan-end, 0.0001312 secs]
2021-05-19T00:45:29.669+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.670+0800: [GC concurrent-mark-end, 0.0009429 secs]
2021-05-19T00:45:29.670+0800: [GC remark, 0.0010988 secs]
2021-05-19T00:45:29.671+0800: [GC cleanup 75M->74M(100M), 0.0003737 secs]
2021-05-19T00:45:29.672+0800: [GC concurrent-cleanup-start]
2021-05-19T00:45:29.672+0800: [GC concurrent-cleanup-end, 0.0000206 secs]
2021-05-19T00:45:29.673+0800: [GC pause (G1 Evacuation Pause) (young) 82M->70M(100M), 0.0015186 secs]
2021-05-19T00:45:29.675+0800: [GC pause (G1 Evacuation Pause) (mixed) 78M->64M(100M), 0.0022592 secs]
2021-05-19T00:45:29.679+0800: [GC pause (G1 Evacuation Pause) (mixed) 70M->65M(100M), 0.0014884 secs]
2021-05-19T00:45:29.680+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 66M->66M(100M), 0.0006846 secs]
2021-05-19T00:45:29.681+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.681+0800: [GC concurrent-root-region-scan-end, 0.0000456 secs]
2021-05-19T00:45:29.681+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.682+0800: [GC concurrent-mark-end, 0.0008500 secs]
2021-05-19T00:45:29.682+0800: [GC remark, 0.0010961 secs]
2021-05-19T00:45:29.683+0800: [GC cleanup 72M->72M(100M), 0.0003134 secs]
2021-05-19T00:45:29.684+0800: [GC pause (G1 Evacuation Pause) (young) 75M->68M(100M), 0.0017291 secs]
2021-05-19T00:45:29.687+0800: [GC pause (G1 Evacuation Pause) (mixed) 77M->70M(100M), 0.0025035 secs]
2021-05-19T00:45:29.691+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 73M->71M(100M), 0.0014056 secs]
2021-05-19T00:45:29.692+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.692+0800: [GC concurrent-root-region-scan-end, 0.0001464 secs]
2021-05-19T00:45:29.692+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.693+0800: [GC concurrent-mark-end, 0.0009321 secs]
2021-05-19T00:45:29.693+0800: [GC remark, 0.0011006 secs]
2021-05-19T00:45:29.694+0800: [GC cleanup 78M->78M(100M), 0.0003301 secs]
2021-05-19T00:45:29.695+0800: [GC pause (G1 Evacuation Pause) (young) 79M->74M(100M), 0.0013411 secs]
2021-05-19T00:45:29.698+0800: [GC pause (G1 Evacuation Pause) (mixed) 81M->73M(100M), 0.0018896 secs]
2021-05-19T00:45:29.700+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 74M->73M(100M), 0.0007626 secs]
2021-05-19T00:45:29.700+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.700+0800: [GC concurrent-root-region-scan-end, 0.0000164 secs]
2021-05-19T00:45:29.700+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.702+0800: [GC concurrent-mark-end, 0.0010740 secs]
2021-05-19T00:45:29.702+0800: [GC remark, 0.0012480 secs]
2021-05-19T00:45:29.703+0800: [GC cleanup 82M->82M(100M), 0.0004452 secs]
2021-05-19T00:45:29.704+0800: [GC pause (G1 Evacuation Pause) (young)-- 83M->82M(100M), 0.0013198 secs]
2021-05-19T00:45:29.706+0800: [GC pause (G1 Evacuation Pause) (mixed)-- 85M->85M(100M), 0.0007048 secs]
2021-05-19T00:45:29.706+0800: [Full GC (Allocation Failure) 85M->72M(100M), 0.0134278 secs]
2021-05-19T00:45:29.720+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 74M->73M(100M), 0.0019245 secs]
2021-05-19T00:45:29.722+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.722+0800: [GC concurrent-root-region-scan-end, 0.0000880 secs]
2021-05-19T00:45:29.722+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.723+0800: [GC pause (G1 Humongous Allocation) (young)-- 77M->75M(100M), 0.0013619 secs]
2021-05-19T00:45:29.725+0800: [GC pause (G1 Evacuation Pause) (young) 77M->75M(100M), 0.0008103 secs]
2021-05-19T00:45:29.726+0800: [GC concurrent-mark-end, 0.0033717 secs]
2021-05-19T00:45:29.726+0800: [GC remark, 0.0012500 secs]
2021-05-19T00:45:29.727+0800: [GC cleanup 77M->77M(100M), 0.0004065 secs]
2021-05-19T00:45:29.728+0800: [GC pause (G1 Evacuation Pause) (young)-- 77M->76M(100M), 0.0008329 secs]
2021-05-19T00:45:29.729+0800: [GC pause (G1 Humongous Allocation) (young)-- 77M->77M(100M), 0.0010191 secs]
2021-05-19T00:45:29.730+0800: [Full GC (Allocation Failure) 77M->74M(100M), 0.0031904 secs]
2021-05-19T00:45:29.733+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark) 76M->75M(100M), 0.0012407 secs]
2021-05-19T00:45:29.735+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.735+0800: [GC concurrent-root-region-scan-end, 0.0000535 secs]
2021-05-19T00:45:29.735+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.735+0800: [GC pause (G1 Evacuation Pause) (young)-- 76M->76M(100M), 0.0010960 secs]
2021-05-19T00:45:29.736+0800: [Full GC (Allocation Failure) 76M->76M(100M), 0.0023247 secs]
2021-05-19T00:45:29.739+0800: [GC concurrent-mark-abort]
2021-05-19T00:45:29.739+0800: [GC pause (G1 Evacuation Pause) (young)-- 77M->77M(100M), 0.0027059 secs]
2021-05-19T00:45:29.742+0800: [Full GC (Allocation Failure) 77M->75M(100M), 0.0026869 secs]
2021-05-19T00:45:29.745+0800: [GC pause (G1 Evacuation Pause) (young)-- 76M->76M(100M), 0.0010872 secs]
2021-05-19T00:45:29.746+0800: [Full GC (Allocation Failure) 76M->75M(100M), 0.0035007 secs]
2021-05-19T00:45:29.750+0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark)-- 76M->76M(100M), 0.0015863 secs]
2021-05-19T00:45:29.751+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.751+0800: [GC concurrent-root-region-scan-end, 0.0000255 secs]
2021-05-19T00:45:29.751+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.751+0800: [GC pause (G1 Humongous Allocation) (young) 76M->76M(100M), 0.0008159 secs]
2021-05-19T00:45:29.752+0800: [Full GC (Allocation Failure) 76M->75M(100M), 0.0023190 secs]
2021-05-19T00:45:29.755+0800: [GC pause (G1 Evacuation Pause) (young) 76M->75M(100M), 0.0010713 secs]
2021-05-19T00:45:29.756+0800: [GC concurrent-mark-abort]
2021-05-19T00:45:29.756+0800: [GC pause (G1 Evacuation Pause) (young)-- 76M->76M(100M), 0.0008249 secs]
2021-05-19T00:45:29.757+0800: [Full GC (Allocation Failure) 76M->76M(100M), 0.0021754 secs]
2021-05-19T00:45:29.760+0800: [GC pause (G1 Evacuation Pause) (young)-- 77M->77M(100M), 0.0011265 secs]
2021-05-19T00:45:29.761+0800: [Full GC (Allocation Failure) 77M->76M(100M), 0.0022905 secs]
2021-05-19T00:45:29.763+0800: [Full GC (Allocation Failure) 76M->76M(100M), 0.0026052 secs]
2021-05-19T00:45:29.766+0800: [GC pause (G1 Evacuation Pause) (young) 76M->76M(100M), 0.0011091 secs]
2021-05-19T00:45:29.767+0800: [GC pause (G1 Evacuation Pause) (young) (initial-mark) 76M->76M(100M), 0.0008196 secs]
2021-05-19T00:45:29.768+0800: [GC concurrent-root-region-scan-start]
2021-05-19T00:45:29.768+0800: [GC concurrent-root-region-scan-end, 0.0000298 secs]
2021-05-19T00:45:29.768+0800: [GC concurrent-mark-start]
2021-05-19T00:45:29.768+0800: [Full GC (Allocation Failure) 76M->250K(100M), 0.0022981 secs]
2021-05-19T00:45:29.771+0800: [GC concurrent-mark-abort]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOfRange(Arrays.java:3664)
at java.lang.String.<init>(String.java:207)
at java.lang.StringBuilder.toString(StringBuilder.java:407)
at GCLogAnalysis.generateGarbage(GCLogAnalysis.java:58)
at GCLogAnalysis.main(GCLogAnalysis.java:25)
同样可以看出G1GC也是有类似于CMSGC一样的标记清除步骤。
| 日志 | 含义 |
|---|---|
| [GC pause (G1 Evacuation Pause) (young) 29M->10093K(100M), 0.0032925 secs] | 转移暂停,young模式,从29M压缩到10M,花费了多少时间 |
| [GC pause (G1 Evacuation Pause) (mixed) 70M->65M(100M), 0.0014884 secs] | 混合模式 |
下图同样是G1的日志图,打印出了更详细的细节,下方更说明了图中标记的含义:

1 表示 GC 发生的时间,一般使用可读的方式打印;
2 表示日志表明是 G1 的“转移暂停: 混合模式”,停顿了约 223ms;
3 表明由 8 个 Worker 线程并行执行,消耗了 214ms;
4 表示 Diff 越小越好,说明每个工作线程的速度都很均匀;
5 表示外部根区扫描,外部根是堆外区。JNI 引用,JVM 系统目录,Classloaders 等;
6 表示更新 RSet 的时间信息;
7 表示该任务主要是对 CSet 中存活对象进行转移(复制);
8 表示花在 GC 之外的工作线程的时间;
9 表示并行阶段的 GC 总时间;
10 表示其他清理活动;
11表示收集结果统计;
12 表示时间花费统计。
# 可视化工具
gceasy
GCViewer
使用脚本简单过滤
# Linux耗时的三维度
在GC日志中也能看到这三个时间维度,下表做了解释,一般只关注real即可。
| 维度 | 含义 |
|---|---|
| real | 实际花费的时间,指的是从开始到结束所花费的时间。比如进程在等待 I/O 完成,这个阻塞时间也会被计算在内; |
| user | 进程在用户态(User Mode)所花费的时间,只统计本进程所使用的时间,注意是指多核; |
| sys | 进程在核心态(Kernel Mode)花费的 CPU 时间量,指的是内核中的系统调用所花费的时间,只统计本进程所使用的时间。 |
JVM入门与进阶 →