动态代理导致的Metaspace OOM(元空间内存溢出)问题

2024-04-16 05:28

本文主要是介绍动态代理导致的Metaspace OOM(元空间内存溢出)问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

个人博客地址:https://blog.flycat.tech/archives/1710866783664

背景

我们团队的一个项目,测试环境最近隔三岔五报错,虽然不是生产环境,但既然有报错那还是得排查下,以免带到了生产环境导致事故。

登录上测试环境服务器,查了下日志,发现是Metaspace内存溢出。

image.png

思路

1、首先我们知道,JDK1.8的Metaspace是在堆外内存的,那么堆分析神器MAT在此案例中没有用武之地;
2、Metaspace中存放的内容包括类结构信息、常量池(编译时字面量等)、字节码等等
3、内存溢出是运行时发生的,考虑到大量的框架用到了动态代理生成字节码等技术,可以将关注点放在生成了大量的类上面
4、由于测试环境是偶尔发生,说明需要请求积累到一定的量才会发生,本地调试直接调对应报错的接口的话可能没法复现出来,此时可以使用postman或jmeter等进行简单压测

复现

因为是测试环境,直接拉test分支在本地跑就好了,使用jmeter调用报错接口,设置20个并发进行压测。
打开Visual VM工具,连接到对应进程,在压测过程中,虽然没有发生Metaspace内存溢出,但是发现Metaspace确实一直在上涨。

CleanShot 2024-03-20 at 00.37.05@2x.png

排查

JDK1.8的Metaspace区域是保存字面量和符号引用字面量就是类中的字符串常量,符号引用就是类元数据信息,父类、接口、属性、方法名等,那么首先排查是否有大量动态代理类加载。

应用启动变量增加几个参数:

-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
-XX:+TraceClassLoading
-XX:+TraceClassUnloading

继续对接口进行压测,一开始有一大堆乱七八糟的日志信息,不过继续压了一会以后,日志中频繁出现了一个代理类的加载信息:com.alibaba.fastjson.serializer.ASMSerializer_1_RespResult

CleanShot 2024-03-20 at 00.35.55@2x.png

因此可以确定是代理类 com.alibaba.fastjson.serializer.ASMSerializer_1_RespResult加载太多次问题,此时基本可以锁定是fastjson使用方式错误问题。

找到fastjson依赖包下找到 com.alibaba.fastjson.serializer路径,发现有一个ASMSerializerFactory的类,在这个类中搜索ASMSerializer_关键字,发现类名生成规则如下:

String className = "ASMSerializer_" + seed.incrementAndGet() + "_" + clazz.getSimpleName();

跟加载的类完全吻合。打上条件断点调接口,根据debug堆栈信息发现是引入的公司内部开发的链路追踪组件包,其实现了ResponseBodyAdvice在结果返回之前拦截,对数据进行脱敏后记录在链路追踪上下文中。

搜下整个链路使用fastjson的情况(可以使用打断点方式),定位到有一处不正规使用方式:

CleanShot 2024-03-20 at 00.40.00.png

CleanShot 2024-03-20 at 00.41.24.png

使用fastjson的SerializeConfig。SerializeConfig创建时默认会创建一个ASM代理类用来实现对目标对象的序列化。也就是上面被频繁创建的类 com.alibaba.fastjson.serializer.ASMSerializer_1_RespResult,如果我们复用SerializeConfig,fastjson会去寻找已经创建的代理类,
从而复用。但是如果new SerializeConfig(),则找不到原来生成的代理类,就会一直去生成新的RespResult代理类。

new SerializeConfig构造方法

修复方案

改成只初始化一次SerializeConfig即可

结论

  1. fastjson的SerializeConfig自定义类的序列化方式有坑,请注意。
  2. 对于使用了ASM等字节码增强工具的类库,在使用他们时请多加小心(尤其是JDK1.8以后)

这篇关于动态代理导致的Metaspace OOM(元空间内存溢出)问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907900

相关文章

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

Redis 热 key 和大 key 问题小结

《Redis热key和大key问题小结》:本文主要介绍Redis热key和大key问题小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、什么是 Redis 热 key?热 key(Hot Key)定义: 热 key 常见表现:热 key 的风险:二、

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊

Spring Boot中JSON数值溢出问题从报错到优雅解决办法

《SpringBoot中JSON数值溢出问题从报错到优雅解决办法》:本文主要介绍SpringBoot中JSON数值溢出问题从报错到优雅的解决办法,通过修改字段类型为Long、添加全局异常处理和... 目录一、问题背景:为什么我的接口突然报错了?二、为什么会发生这个错误?1. Java 数据类型的“容量”限制

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图

SpringBoot项目中报错The field screenShot exceeds its maximum permitted size of 1048576 bytes.的问题及解决

《SpringBoot项目中报错ThefieldscreenShotexceedsitsmaximumpermittedsizeof1048576bytes.的问题及解决》这篇文章... 目录项目场景问题描述原因分析解决方案总结项目场景javascript提示:项目相关背景:项目场景:基于Spring