Java反序列化json内存溢出_fastJson与一起堆内存溢出'血案'

本文介绍了由于Java反序列化json过程中出现内存溢出的问题,详细分析了问题的原因,涉及fastjson库。通过日志、JVM命令和内存分析工具MAT的使用,定位到问题出在配置类PersonalityStrengthenConfig的cost字段,由于反序列化错误模式导致每次反序列化都会增加null,最终导致内存溢出。解决方案是确保在序列化时添加SerializerFeature.IgnoreNonFieldGetter参数,避免非字段get方法的序列化。
摘要由CSDN通过智能技术生成

现象

QA同学反映登录不上服务器

排查问题1–日志级别

查看log,发现玩家登录的时候抛出了一个java.lang.OutOfMemoryError

大概代码是向Redis序列化一个PlayerMirror镜像数据,但是在JSON.toJSONString的时候出现了错误.比较清晰,即序列化的时候expandCapacity,内存不足。

又看了一下日志,有好几个OutOfMemoryError,都是类似于用fastjson序列化PlayerMirror报的错误

又仔细看了一下server目录,发现了几个.hprof,说明确实发生了堆内存溢出,因为启动参数增加了’-XX:+HeapDumpOnOutOfMemoryError’

at java.lang.OutOfMemoryError.()V (OutOfMemoryError.java:48)

at com.alibaba.fastjson.serializer.SerializeW

riter.expandCapacity(I)V (SerializeWriter.java:249)复制

-rw------- 1 xx xx 2043416350 Nov 24 11:37 java_pid8068.hprof

-rw------- 1 xx xx 2028797313 Nov 24 11:17 java_pid4671.hprof

-rw------- 1 xx xx 1477222612 Nov 23 23:25 java_pid31563.hprof复制

排查问题2–JVM命令级别

使用了jvm命令初步排查一下问题 jstat -gcutil pid

jstat -gc pid

jmap -histo pid

jmap -heap pid

jstat看到老年代基本已经满了

jmap看到排名前两位的分别是Object[]和char[]

num #instances #bytes class name

----------------------------------------------

1: 146219 741203672 [Ljava.lang.Object;

2: 2842356 639498168 [C复制

排查问题3–专业工具级别

因为了hprof,所以只需要用专业的内存分析工具mat即可 mat#Open Heap Dump,载入后直接出来一个Getting Started Wizard#Leak Suspects Report,即内存泄露的报告,选择finish 两个怀疑的问题:

其中有一个JSONArray的实例就占用了大约700M内存

另外一个是线程的local Variables占用了500M内存

f238e6b3dca3335c5dc46349efb58aad.png

点开问题1详情,发现这个JSONArray是配置类PersonalityStrengthenConfig#cost字段,仔细看一下这

Java 中的 JSON 序列化和反序列化可以使用许多第三方库来实现,比如 Jackson、Gson、FastJson 等。这里以 Jackson 库为例,介绍如何进行 JSON 序列化和反序列化。 ### Jackson 序列化 Jackson 序列化可以将 Java 对象转换为 JSON 字符串。示例代码如下: ```java ObjectMapper objectMapper = new ObjectMapper(); MyObject myObject = new MyObject(); // 要序列化的 Java 对象 String json = objectMapper.writeValueAsString(myObject); // 序列化成 JSON 字符串 ``` 在上面的代码中,ObjectMapper 是 Jackson 序列化和反序列化的核心类。writeValueAsString() 方法将 Java 对象序列化成 JSON 字符串。 如果要对序列化后的 JSON 字符串进行格式化,可以使用 ObjectMapper 的 writerWithDefaultPrettyPrinter() 方法: ```java ObjectMapper objectMapper = new ObjectMapper(); MyObject myObject = new MyObject(); // 要序列化的 Java 对象 String json = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(myObject); // 序列化成格式化后的 JSON 字符串 ``` ### Jackson 反序列化 Jackson 反序列化可以将 JSON 字符串转换为 Java 对象。示例代码如下: ```java ObjectMapper objectMapper = new ObjectMapper(); String json = "{\"name\":\"Tom\", \"age\":20}"; // 要反序列化JSON 字符串 MyObject myObject = objectMapper.readValue(json, MyObject.class); // 反序列化Java 对象 ``` 在上面的代码中,readValue() 方法将 JSON 字符串反序列化Java 对象。第一个参数是要反序列化JSON 字符串,第二个参数是目标 Java 类型。 ### Jackson 注解 Jackson 序列化和反序列化还支持一些注解,用于控制序列化和反序列化的行为。比如,可以使用 @JsonProperty 注解指定 JSON 字段名: ```java public class MyObject { @JsonProperty("user_name") private String name; private int age; // ... } ``` 在上面的代码中,@JsonProperty("user_name") 注解指定了 JSON 字段名为 "user_name",而不是默认的 "name"。这样,在序列化和反序列化时,Jackson 就会使用指定的字段名。 除了 @JsonProperty 注解,Jackson 还支持许多其他注解,比如 @JsonIgnore、@JsonFormat、@JsonInclude 等。这些注解可以用于控制序列化和反序列化的行为,更多的注解用法可以参考 Jackson 的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值