FastJson不成想还有个版本2啊:序列化大字符串报错
背景
发现陷入了一个怪圈,写文章的话,感觉只有大bug或比较值得写的内容才会写,每次一写就是几千字,争取写得透彻一些,但这样,我也挺费时间,读者也未必有这么多时间看。
我想着,日常遇到的小bug、平时工作中的一些小的心得体会,都还是可以写写,这样也才是最贴近咱们作为一线开发生活的,也不必非得是个完整且深入的主题,因此,准备搞一个专门的标签:点滴记录Coding之路来记录这些。
ok,咱们开始,最近,手下开发小哥去帮忙做一个其他组的项目,但遇到一些解决不了的问题就会找我帮忙看。最近来问我了一个问题,说是他有个接口,调用会报内存溢出,在本机就能复现,不知道咋回事。
上下文
接口代码如下:
在一个for循环里面,会去执行sql,查询数据库记录,存到dataList这个列表中,然后序列化为json,这里呢,他们使用的是fastjson。
他调用接口给我演示了下,上面代码不是个循环嘛,跑着跑着就报错了,报错的栈大概如下(这个栈来自网上,问题类似):
Exception in thread "pool-4-thread-1" java.lang.OutOfMemoryError
at com.alibaba.fastjson2.JSONWriterUTF16.writeNameRaw(JSONWriterUTF16.java:561)
at com.alibaba.fastjson2.writer.FieldWriterImpl.writeFieldName(FieldWriterImpl.java:143)
at com.alibaba.fastjson2.writer.ObjectWriter_3.write(Unknown Source)
at com.alibaba.fastjson2.writer.ObjectWriterImplList.write(ObjectWriterImplList.java:278)
at com.alibaba.fastjson2.JSON.toJSONString(JSON.java:1757)
.....
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
排查
刚看到这个,也没啥思路,一开始还以为是内存、gc之类的问题,看了会后,决定在报错的地方打断点看下,到底为啥报这个。
我这边debug了两圈后,发现都是走到如下位置的时候报错:
这个函数,大概就是,在初步序列化对象为字符串后,要计算字符串的长度,然后看看这个长度能不能写入到底层JsonWriter的字符数组中(会比较字符串的长度和JsonWriter中数组的长度),如果JsonWriter中数组长度过小,这里就要触发扩容。
而扩容前,如果发现要扩容的大小大于maxArraySize(一个配置项),就会抛这个内存溢出的溢出,并不是真的发生了内存溢出。
当时debug的时候,看到maxArraySize大概是60w多,大概就是60多m大小。当时就很纳闷,是不是查出来的数据太大了,不然即使扩容啥的,也不可能大于60M,后面果然看到数据竟然达到了几十M大小,由于这个系统我也没参与,这块业务合不合理就不管了,解决问题就行。
然后我就看了下,maxArraySize赋值的地方,看看这个能不能改大点,改大了就没事了。
protected final int maxArraySize;
protected JSONWriter(Context context, Charset charset) {
this.context = context;
this.charset = charset;
this.utf8 = charset == StandardCharsets.UTF_8;
this.utf16 = charset == StandardCharsets.UTF_16;
quote = (context.features & Feature.UseSingleQuotes.mask) == 0 ? '"' : '\'';
// 64M or 1G
maxArraySize = (context.features & LargeObject.mask) != 0 ? 1073741824 : 67108864;
}
这边果然看到,有个注释,64M OR 1G,果然,是个配置项,看起来,这个配置项是受LargeObject这个控制的。
一开始,我以为这个是com.alibaba.fastjson.serializer.SerializerFeature
里的枚举项,结果并不是,没发现是JsonWriter的配置项:
com.alibaba.fastjson2.JSONWriter.Feature
知道是配置项了,问题是怎么配置呢?仔细看了各个方法,都不能传这种JsonWriter的枚举啊
后边,看了半天,发现这个方法可以传JsonWriter的feature:
问题是,这个defaultFeatures是int,32位整数,每个bit代表一个特性,也就是说,我得自己计算将LargeObject这个bit置为1后,整个int的值。
大家看这个feature的值:
// 十进制为:8589934592, 二进制为:001000000000000000000000000000000000
LargeObject(1L << 33),
我就根据这个,自己把这个bit设为1,然后算了个值出来,结果,跟我说,超过了int的范围,导致我没法传参进去。
解决
我都服了,然后开始在网上看看有没有类似的问题,结果只找到了一篇文章。
https://blog.csdn.net/m0_68736501/article/details/132078314
解决办法是说,升级jar包版本到2.0.16,里面有个方法,可以传JsonWriter的Feature枚举值进去:
JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.LargeObject).getBytes(DEFAULT_CHARSET);
结果我看了我们版本,都2.0.19了,版本比他还高,结果没看到这个方法。服了,难道高版本还把这个方法删了?
然后小伙子看我忙,就说他回去再研究研究,我说行,我也网上查下。
后边也找到篇文章,让他试试:https://www.exyb.cn/news/show-5352725.html,他没说有没有效果,但是过了一阵,他跟我说,知道问题了。
行吧,我给大家梳理下结论,我们的pom引入的依赖是:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.19</version>
</dependency>
这个内部其实还依赖了另外的jar:
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension</artifactId>
</dependency>
而上面的这个,又依赖了:
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
差不多,就是下图这样的关系:
然后,导致我们项目中,其实有两个JSON类:
com.alibaba.fastjson2.JSON; 位于fastjson2-2.0.19.jar
com.alibaba.fastjson.JSON; 位于fastjson-2.0.19.jar
而之前我们导入的是下面那个,也就是传统的com.alibaba.fastjson.JSON,里面就是没法传JsonWriter的Feature枚举的,只有上面那个才有:
com.alibaba.fastjson2.JSON#toJSONString(java.lang.Object, com.alibaba.fastjson2.JSONWriter.Feature...)
/**
* Serialize Java Object to JSON {@link String} with specified {@link JSONReader.Feature}s enabled
*
* @param object Java Object to be serialized into JSON {@link String}
* @param features features to be enabled in serialization
*/
static String toJSONString(Object object, JSONWriter.Feature... features) {
所以,剩下的事情,简单了,修改import的类为com.alibaba.fastjson2.JSON即可,然后序列化时传入feature:
String previewDataJson = JSON.toJSONString(dataList,LargeObject);
问题解决。
结论
新项目建议还是用jackson算了,当然了,这个项目也不是我主导,而且都开发快完成了,就这样吧,一般大问题也没有,有就再改吧。
FastJson不成想还有个版本2啊:序列化大字符串报错的更多相关文章
- wcf序列化大对象时报错:读取 XML 数据时,超出最大
错误为: 访问服务异常:格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出 错: request.InnerException 消息是“反序 ...
- Atitit mac os 版本 新特性 attilax大总结
Atitit mac os 版本 新特性 attilax大总结 1. Macos概述1 2. 早期2 2.1. Macintosh OS (系统 1.0) 1984年2 2.2. Mac OS 7. ...
- pathinfo()在php不同版本中对于对多字节字符处理的不同结果
phpinfo()函数在处理路径时,在php的低版本中无法处理多字节字符,这里测试的是php5.3和php5.6 的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...
- 调试接口,返回的json数据,我定义了一个类,用来序列化,其中有一个字段定义为string 然后序列化的时候报错
调试接口,返回的json数据,我定义了一个类,用来序列化,其中有一个字段定义为string 然后序列化的时候报错 在需要解析的类型类上加上声明 eg:
- java分享第十三天(fastjson生成和解析json数据,序列化和反序列化数据)
fastjson简介:Fastjson是一个Java语言编写的高性能功能完善的JSON库.fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jack ...
- fastjson生成和解析json数据,序列化和反序列化数据
本文讲解2点: 1. fastjson生成和解析json数据 (举例:4种常用类型:JavaBean,List<JavaBean>,List<String>,List<M ...
- c# json序列化 意外字符i 意外字符ï 解决方案
今天使用DataContractJsonSerializer遇到了这个问题 这是个蛋疼的问题,折腾了我好久,反复检查对象和json字符串,没发现什么问题,而且错误提示还看走眼了,是ï不是i 现公布解决 ...
- mongodb不同版本之间有很大的差异
今天主要说下我为了给mongodb数据库添加authorization,大家应该知道,mongo默认是无auth运行的.这可能是方便小伙伴学习命令吧. 由于之前发布的一个项目,在亚马逊的云上,处于内部 ...
- JDK版本过高,导致Eclipse报错
1.JDK版本如果比较高,而使用的eclipse版本比较低,导致在eclispe中不能识别而报错. 2.点击Attach Source添加rt.jar后,又出现如下错误 3.这样的错误就是由于ec ...
- 1.1.6版本Druid连接MSSQLServer 2008 R2报错The query timeout value -1 is not valid. #2210
https://github.com/alibaba/druid/releases/tag/1.1.8问题已修复,请使用新版本 xhhwc commented on 21 Dec 2017 1.1.6 ...
随机推荐
- ESLint: Expected a space before ‘/>;‘, but not found. (vue/html-closing-bracket-spacing)
文件->设置->编辑器->代码样式->HTML->其他-->在空的标签(打钩)
- 在 Transformers 中使用对比搜索生成可媲美人类水平的文本 🤗
1. 引言 自然语言生成 (即文本生成) 是自然语言处理 (NLP) 的核心任务之一.本文将介绍神经网络文本生成领域当前最先进的解码方法 对比搜索 (Contrastive Search).提出该方法 ...
- Java 世界的法外狂徒:反射
概述 反射(Reflection)机制是指在运行时动态地获取类的信息以及操作类的成员(字段.方法.构造函数等)的能力.通过反射,我们可以在编译时期未知具体类型的情况下,通过运行时的动态查找和调用. 虽 ...
- vue 中render执行流程梳理
用了多年vue 今天对自己了解的render 做一个梳理 一.使用template模板 先从vue 初始化开始: 众所周知项目的main.js中定义了 var app = new Vue({})这vu ...
- Django自定义视图类及实现请求参数和返回参数加解密
django rest_framework中GenericAPIView配合拓展类mixin或者视图集viewset可以复用其代码,减少自己编写的代码量.下面我要实现自己的视图类,以减少代码量新建一个 ...
- 代码随想录算法训练营Day27 回溯算法|39. 组合总和 40.组合总和II 131.分割回文串
代码随想录算法训练营 39. 组合总和 题目链接:39. 组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 ta ...
- 代码随想录算法训练营Day16二叉树|104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数
代码随想录算法训练营 代码随想录算法训练营Day16二叉树|104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数 104.二叉树的最大深度 题目 ...
- Mysql DDL执行方式-pt-osc介绍 | 京东云技术团队
1 引言 大家好,接着上次和大家一起学习了<MySQL DDL执行方式-Online DDL介绍>,那么今天接着和大家一起学习另一种MySQL DDL执行方式之pt-soc. 在MySQL ...
- 解决google翻译出错问题
解决google翻译问题 一.为什么失效 因为google把google翻译的API给关闭了,导致翻译不了. 据网上说是服务器耗钱,但盈利不够导致的. 二.可修复的前提 国内还存有服务器可以用API ...
- JS异步解决方案及优缺点
1. 回调函数 优点: 解决了同步的问题(只要有一个任务耗时长后面的任务都会等待,会拖延程序执行) 缺点: 回调地狱 不能用try catch捕获 不能用 return setTimeout(( ...