如何分析GC日志?
GC日志的产生
在Java运行时,当内存分配器发现无法找到足够内存空间给新对象分配时,就会导致GC的发生。在GC进行时,JVM会对应用程序进行暂停,去回收无用内存对象。产生的GC日志记录了每次GC的信息和GC期间堆的使用情况。
记录GC日志
我们可以通过以下命令记录GC日志:
java -XX:+PrintGC -XX:+PrintGCDetails -Xloggc:<log_file_path> YourProgram
其中:
-XX:+PrintGC
:打印GC信息。-XX:+PrintGCDetails
:打印GC详细信息。-Xloggc:<log_file_path>
:将GC日志记录到指定文件中。
GC日志分析
1. 分析GC类型
GC类型有很多种,每种都有自己的影响和解决方法。我们可以通过GC日志中的以下字段来确定GC类型:
Full GC
Minor GC
Major GC
Concurrent GC
Serial GC
Parallel GC
G1GC
下面介绍以下几种类型的GC:
Minor GC
:一般是指Young Generation区域的GC,收集年轻代的对象。通过GC日志可以看到[GC (Allocation Failure)]
,这种情况是分配内存空间失败导致的GC。Major GC
:指Old Generation区域的GC,收集老年代的对象。Full GC
:是对整个Java堆的清理,包括Young Gen、Tenured Gen(也就是老年代)以及Perm Gen区域(永久代)的GC。
2. 分析GC时间和原因
在GC日志中,我们可以看到诸如以下信息,通过向前跟踪,我们可以确认GC时间和原因。
2021-04-27T12:48:58.456+0800: 1.030: [GC (Allocation Failure) 1.032: [ParNew: 34155K->3775K(38336K), 0.0051219 secs] 34155K->9435K(123904K), 0.0052869 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
我们可以看到,GC发生在2021-04-27T12:48:58.456+0800时刻,由于空间分配失败(Allocation Failure)导致的GC。
3. 分析GC前后堆内存状况
通过GC日志,我们可以采集到GC发生时Young Gen和Old Gen的大小、使用空间、总空间等信息,从而查看GC前后堆内存的变化情况,这对于我们了解程序内的内存使用情况非常重要。
2021-04-27T12:48:58.462+0800: 1.035: [GC (Allocation Failure) 1.036: [ParNew: 38336K->3466K(38336K), 0.0034323 secs] 78827K->60557K(207872K), 0.0035211 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
在以上GC日志中,我们可以看到Young Gen由原来的38M变成了3.4M,Old Gen由原来的78.8M变成了60.5M,总堆内存从207.9M变成了20.7M,这表明该场景下发生了大量的内存回收,程序的内存使用过于频繁。
示例说明
示例1
2021-04-27T13:08:51.583+0800: 359.358: [GC (Allocation Failure) 359.358: [PSYoungGen: 461760K->16833K(471872K)] 553086K->126234K(1544192K), 0.0449684 secs] [Times: user=0.08 sys=0.05, real=0.05 secs]
以下是该GC日志的分析:
- GC发生在2021-04-27T13:08:51.583+0800时刻。
- 此GC为Young Gen的GC,分配失败导致的GC。
- Young Gen在GC前(461760K)与GC后(16833K)的差额为444927K,总容量为471872K。
- JVM堆总容量在GC前(553086K)与GC后(126234K)的差额为426852K,总容量为1544192K。
从以上分析中,可以看到Young Gen的使用空间在短暂时间内急剧增加,尤其在分配内存的时候,很容易达到Young Gen的额定容量,因此需要关注程序的内存使用情况。
示例2
2021-04-27T14:18:11.284+0800: 4469.047: [Full GC (Metadata GC Threshold) [PSYoungGen: 0K->0K(87296K)] [ParOldGen: 139950K->141324K(139776K)] 139950K->141324K(227072K), [Metaspace: 30784K->30784K(1089536K)], 0.2603214 secs] [Times: user=0.55 sys=0.00, real=0.26 secs]
以下是该GC日志的分析:
- GC发生在2021-04-27T14:18:11.284+0800时刻。
- 此GC为Full GC,扫描了整个Java堆内存。
- 整个堆的使用空间在GC前(139950K)和GC后(141324K)没有太大变化。
- Java堆最大容量为227072K。
从以上分析中,可以看到整个Java堆内存扫描花费的时间(0.2603214秒),因此需要深入了解该场景的具体耗时和内存占用原因。