arthas 异常排查(一 ) 一次内存泄露
1. 查看服务发现内存消耗严重
图中的5638进程java程序内存已经来到了52%,即8G.肯定是不正常的.

2. 下载arthas来分析数据.
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
# 选择5638进程的java程序.

3. 使用memory查看内存情况
使用memory 查看内存分布情况.

发现nonheap(非堆内存)存在异常占用.且metaspace(元空间)中占用也异常.由此推测是类加载器泄露或动态生成过多类.
4. 通过jvm查看
使用jvm查看内存分布情况.

发现类加载统计次数非常高.属于异常情况.
5. 使用classloader查看类加载详情

通过连续的键入classloader.发现com.alibaba.fastjson2.util.DynamicClassLoader这个类加载器loaded次数持续上涨.
使用classloader --list 可以查看类加载器的hash值,用于后续的过滤.
6. 检查代码,找出fastjson相关代码.做测试排查
最后检查到serializeConfig这里存在问题.config只需存于一份即可,无须每次调用都创建一次.
// others
SerializeConfig serializeConfig = new SerializeConfig();
// 驼峰转下划线
serializeConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
String reqStr = JSON.toJSONString(req, serializeConfig);
跟踪serializeConfig代码发现创建对象时会在无参构造中创建ObjectWriterProvider对象.
public class SerializeConfig {
.......
public SerializeConfig() {
this(new ObjectWriterProvider());
}
public SerializeConfig(ObjectWriterProvider provider) {
this.fieldBased = false;
this.provider = provider;
}
}
而在翻阅fastjson的github仓库的时候,fastjson的开发人员回答的是provider单例.

7. 验证
通过通过sc命令查看类加载情况
查找 com.alibaba.fastjson2包下的类.并通过类加载器过滤该类所创建的类.
sc -d com.alibaba.fastjson2.* -c 21d2b7f7 -n 20
发现存在大量的writer类使用后没有销毁.

8. 修改
将SerializeConfig对象上升到类变量中.保持单例.
private SerializeConfig serializeConfig = new SerializeConfig();
......
// 驼峰转下划线
serializeConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
String reqStr = JSON.toJSONString(req, serializeConfig);