记录一次Metaspace OOM的问题

事件

4.13号测试部署的服务突然爆oom异常

第一次OOM异常如下:

2020-04-14 14:42:43.092 - - [ERROR] Druid-ConnectionPool-Create-755299134 DruidDataSource  (DruidDataSource.java:2699) create connection SQLException, url: jdbc:m
ysql://10.24.65.26:4000/trade_event?characterEncoding=UTF8&socketTimeout=60000&allowMultiQueries=true, errorCode 0, state S1000
java.sql.SQLException: java.lang.OutOfMemoryError: Metaspace
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:877) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:873) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:443) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:389) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1596) ~[druid-1.1.18.jar!/:1.1.18]
        at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1662) ~[druid-1.1.18.jar!/:1.1.18]
        at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2697) [druid-1.1.18.jar!/:1.1.18]
Caused by: java.lang.OutOfMemoryError: Metaspace
2020-04-14 14:42:44.943 - - [ERROR] Druid-ConnectionPool-Create-755299134 DruidDataSource  (DruidDataSource.java:2699) create connection SQLException, url: jdbc:mysql://10.24.65.26:4000/trade_event?characterEncoding=UTF8&socketTimeout=60000&allowMultiQueries=true, errorCode 0, state S1000
java.sql.SQLException: java.lang.OutOfMemoryError: Metaspace
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:877) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:873) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:443) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:389) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
        at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1596) ~[druid-1.1.18.jar!/:1.1.18]
        at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1662) ~[druid-1.1.18.jar!/:1.1.18]
        at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2697) [druid-1.1.18.jar!/:1.1.18]

分析

1、Metaspace区域的oom 多考虑
1)类重复加载
2)加载的class过大
3)类加载器过多导致Metaspace碎片化严重
2、将oom时的内存快照dump下来,使用MAT或者visualvm进行分析

在这里插入图片描述

确实有很多类被加载了

3、分析gc日志
在这里插入图片描述
由于metaspace太小 导致频繁fullgc

4、查看线上对JVM的监控

查看从部署到OOM期间 fullGC次数、metaspace使用情况
结合突增的时间点查看当时的rpc请求、MQ消费等

5、新增两个JVM参数 -XX:+TraceClassLoading -XX:+TraceClassUnloading,观察是什么类创建比较频繁
但是log4j std.log并没有打印出来,需要将结果输出出来

形如这种参数: java -XX:+TraceClassLoading -jar demo-0.0.1-SNAPSHOT.jar > /Users/detail.log

将控制台信息输出到detail.log

而项目中的脚本是这样的 java [jvm参数] -jar xx.jar 2>&1 ,需要改动一下

6、对有改动的代码进行压测 看是否能复现
暂时没有复现

2021-05-24 更新:
使用了新的分析工具Jprofile对之前的内存文件进行分析
可以进行引用源头分析

总结

1、-XX:MetaspaceSize参数
这个参数的含义是 当Metaspace的使用达到size值时,会触发fullgc。
所以这个值如果太小,在项目启动的时候加载的类太多,就会fullgc,导致启动变慢

2、对于项目确实要加载很多类的情形,需要根据实际情况设置
-XX:MaxMetaspaceSize

3、-XX:+UnlockDiagnosticVMOptions,方便后续对JVM情况观察

jcmd 238794  GC.class_stats
238794:
GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions
当遇到MetaspaceOOM异常时,可以尝试以下排查和处理方法: 1. 增加Metaspace内存空间: - 通过调整JVM参数来增加Metaspace的内存空间,可以使用`-XX:MetaspaceSize`和`-XX:MaxMetaspaceSize`参数来设置初始大小和最大大小。 - 适当增加Metaspace的内存空间可以缓解OOM异常,但需要注意不要过度分配内存导致其他部分受影响。 2. 检查是否存在大量动态生成的类: - 使用CGLIB、反射等方式动态生成类会消耗Metaspace的内存。 - 检查代码中是否存在频繁动态生成类的逻辑,考虑优化或减少动态生成类的使用。 3. 检查字符串常量的使用: - Metaspace也存储字符串常量,过多的字符串常量会增加Metaspace的内存压力。 - 检查代码中是否存在大量重复的字符串常量,可以使用字符串常量池或intern()方法来避免重复创建字符串对象。 4. 分析堆栈信息和内存快照: - OOM异常发生时,记录相关堆栈信息和内存快照。 - 使用工具(如MAT、VisualVM等)分析堆栈信息和内存快照,找出可能存在的内存泄漏问题。 5. 优化代码和资源管理: - 检查代码中是否存在不必要的类加载、资源加载或资源未释放的情况。 - 优化代码逻辑,避免重复加载和使用不必要的资源。 6. 升级JDK版本: - Metaspace的实现在不同的JDK版本中可能会有差异,升级到较新的JDK版本可能会提供更好的Metaspace管理和性能。 7. 参考官方文档和社区资源: - 参考Java官方文档、Oracle官方文档以及相关社区资源,了解Metaspace的工作原理和最佳实践。 - 在问题解决过程中,可以参考其他开发者的经验分享和解决方案。 重要的是,处理MetaspaceOOM异常需要综合考虑代码、配置和环境等多个因素,根据具体情况采取相应的措施。如果问题持续存在或难以解决,可以考虑寻求专业的Java性能优化工具或咨询服务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值