最近项目监控后台总是报:老年代内存使用率监控异常,频繁FullGC,30秒一次FullGC,CPU使用率超过90%,造成系统的性能迅速下降。频繁慢sql。总结一下排查JVM内存问题的过程和使用的工具。
1、刚开始发现频繁fullGC,所以查看了GC日志。
系统启动之后3天之后第一次fullGC,垃圾回收之后只释放了1600M左右的内存 都是新生代的内存,老年代几乎已经满了。
之后就开始频繁的Full GC ,几分钟就Full GC一次,最后就是30秒一次Full GC。系统的CPU飙升。当时并没有跑job,没有多大的数据量,老年代的对象只能是3天时间积累起来的,最后定位是内存泄漏。老年代对象无法回收。
2、第二步开始监控和诊断 JVM 堆内对象,需要使用jdk自带的综合性的图形化工具,如 JConsole、VisualVM,但是只能监控本地IDEA启动的程序,不能远程连接线上服务器。
通过监控可以查看程序运行是新生代对象的创建,GC频率,还是老年代对象的积累过程。
java visualVM监控页面
Java jconsole 显示页面
在visualVM中查看堆dump中的对象信息。如下图:
通过本地调试和排查,无法模拟线上复杂的环境,创建的垃圾对象也没有那么多。没有找到原因。
最后只有运维的同学帮我dump 了份线上生产环境的堆dump文件,用一下命令:
需要先用 ps -ef |grep "java" 查看 当前服务运行的Pid.
在执行下面的命令:
jmap -dump:format=b,file=20200513.dump 27379
最后在将生产的文件下载到本地:使用SSh客户端
scp -r ./20200513.dump gaocai@172.**.**.**:/d:/
生成.dump格式的文件,可以使用visualVM装入。开始分析。由于visualVM的软件功能有限,
我又下载了MemoryAnalyzer (MAT)和JProfiler来分析堆dump文件。
使用这两个工具分析需要将.dump文件的扩展名修改为.hprof格式。我先用MAT打开。
在overview页面可以看到大部分的内存 占用是problem内存对象890M。
我用到了Leak Suspects 和 Dominator 定位内存泄漏的问题代码。
1
2
3
4
从上图中可以看出,在VkRedis的MatricsFactory这个类中有一个ConcurrentHashMap对象占用了系统90%的内存。保存的是大量的SimpleMeterRegistry对象。
map的名字是 KEY_METER_REGISTRY_MAP 。在Java源带码中ctrl+N查询MatricsFactory类。发现:
有一个定义成静态的map,名字也和查出来的一样。一天时间里边就保存了80万个Meter 对象。
以上定位到了内存泄漏的问题代码。是架构组的redis中间件有内存泄漏的问题。