fastjson使用JSON.toJSON()方法出现StackOverflowError

Posted 一步一步往上爬的小蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fastjson使用JSON.toJSON()方法出现StackOverflowError相关的知识,希望对你有一定的参考价值。

        上个月底,邮箱每到中午都会收到告警邮件,内容如下:

logLevel = "ERROR" AND 
(message CONTAIN "java.lang.StackOverflowError" OR 
message CONTAIN "java.lang.OutOfMemoryError") 

        既然每天都那么准点,大概率是定时任务导致的了,很轻松就找到了每天中午12点开始跑的定时任务。但是问题代码出现在哪里呢?模拟了同样的入参,去调用该接口,可是无法重现该错误。而打印的日志是不完整的,如下:

org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1055)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:94)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at com.vipshop.mercury.client.filter.MercuryTraceFilter.doFilter(MercuryTraceFilter.java:166)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:209)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:128)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.access$000(ErrorPageFilter.java:66)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:103)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:121)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at de.javakaffee.web.msm.RequestTrackingContextValve.invoke(RequestTrackingContextValve.java:99)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
	at de.javakaffee.web.msm.RequestTrackingHostValve.invoke(RequestTrackingHostValve.java:157)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:509)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1104)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.StackOverflowError: null
	at java.lang.ReflectiveOperationException.<init>(ReflectiveOperationException.java:89)
	at java.lang.reflect.InvocationTargetException.<init>(InvocationTargetException.java:72)
	at sun.reflect.GeneratedMethodAccessor1710.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.alibaba.fastjson.util.FieldInfo.get(FieldInfo.java:544)
	at com.alibaba.fastjson.serializer.FieldSerializer.getPropertyValue(FieldSerializer.java:153)
	at com.alibaba.fastjson.serializer.JavaBeanSerializer.getFieldValuesMap(JavaBeanSerializer.java:797)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1106)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)
	at com.alibaba.fastjson.JSON.toJSON(JSON.java:1108)

        请教了同事,了解到JVM有个参数可以控制StackOverflowError错误日志的行数打印——MaxJavaStackTraceDepth 。配置 -XX:MaxJavaStackTraceDepth=-1 以后,第二天再次出现该错误时,可以准确定位到出现错误的代码行数,代码如下:

log.error("批量保存es数据存在不成功的情况,不成功的item:", JSON.toJSON(item));

        猜测是调用es保存接口失败后,返回的对象有循环引用,导致了StackOverflowError的出现,具体错误很难模拟,也就没继续探究根本原因,因此只是改为 JSON.toJSONString() 方法:

log.error("批量保存es数据存在不成功的情况,不成功的item:", JSON.toJSONString(item));

        注:项目中此时使用的fastjson版本号为 1.2.70

参考链接:

       JVM MaxJavaStackTraceDepth 参数详解 | HeapDump性能社区

       ​​​​​​【避坑】FastJson稍微使用不当就会导致StackOverflow_凡是过往,皆为序章-CSDN博客_fastjson stackoverflowerror

        fastjson序列化出现StackOverflowError - JavaShuo 

        fastjson 相互引用的类实例,调用toJSON报堆栈溢出_大数据知识库

        相互引用的类实例,调用toJSON报堆栈溢出 · Issue #2915 · alibaba/fastjson · GitHub

        Json序列化时重复引用、循环引用的问题 - 代码先锋网

        生成json串的时候栈溢出的解决_小希一夏的博客-CSDN博客_jackson 栈溢出

        fastjson序列化出现StackOverflowError - buguge - 博客园

fasterxml 循环引用导致StackOverflowError线程栈错误_|] 大世界,小人物-CSDN博客

以上是关于fastjson使用JSON.toJSON()方法出现StackOverflowError的主要内容,如果未能解决你的问题,请参考以下文章

fastjson使用JSON.toJSON()方法出现StackOverflowError

fastjson的基本用法,fastjson对日期的处理

Java bean 转 Map

序列化

去除阿里巴巴的JSON-踩雷

fastjson 使用方法大全