1 背景
公司的一个项目,平时运行一直没问题,但是最近,时不时的会报出 java.lang.OutOfMemoryError: GC overhead limit exceeded 错误,然后,java进程就处于假死状态,几天都不会有后台日志更新。
2 问题原因
可以明确的一点是,jvm出现了问题。所以,查看jvm内存使用情况
可以看出,FGC进行了89次,而YGC是23次。这就有点奇怪了,为什么fullGC这么频繁,而且还超过了yangGC次数。所以可以肯定的是和FullGC过于频繁有关。
默认情况下,如果在某一个时间段内,FullGC花费的时间超过 98%,并且GC 回收的内存少于 2%,JVM 就会抛出这个错误。而且抛出这个错误后,jvm将不再进行GC动作,jvm将处于假死状态。
那什么导致的FullGC频繁呢?我们注意到,OldCapacity=2.7G。而当JVM刚启动的时候,默认分配的堆内存为物理内存的1/64,本机内存15G,也就是说会分配230M内存给jvm堆,而老年代默认占8/10堆内存,也就是不到200M,但是现在这个内存是2.7G,很明显是因为某一个业务把大量数据放到内存中,导致老年代堆内存一直在增大导致的,在这个过程中,老年代内存一直无法容纳这么大的数据量,一直进行FullGC,最终在短时间内FullGC过于频繁,最终触发了GC overhead limit exceeded。
为了验证我们的猜想,我们查看业务日志,发现在出现GC overhead limit exceeded之前,某一个用户在查询venn图。
2022.09.07 17:35:23.920 INFO [http-nio-8081-exec-6] com.xxx.xxx.microbereport.controller.module.VennController 38 venn - RequestBody:{"planCode":"xxx","customerEmail":"xxx","currentCompareGroup":""}
2022.09.07 17:39:04.329 WARN [HikariPool-1 housekeeper] com.zaxxer.hikari.pool.HikariPool$HouseKeeper 766 run - HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m3s213ms343µs686ns).
2022.09.07 17:41:21.004 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#0-1-C-1] org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer 718 run - Stopping container due to an Error java.lang.OutOfMemoryError: GC overhead limit exceeded
2022.09.07 17:41:20.999 WARN [cluster-ClusterId{value='63186157d456c1530516ee32', description='null'}-16s3:27017] com.mongodb.diagnostics.logging.SLF4JLogger 91 warn - Exception in monitor thread during notification of server description state change j