Spark TaskResultGetter线程任务序列化时出现StackOverflowError
Spark作业StackOverflowError问题解决与规避建议
部分Spark作业因StackOverflowError失败,报错栈追踪信息如下:
ResultStage 363 (save at Transform.scala:156) failed in 17.392 s due to Job aborted due to stage failure: Task 4 in stage 363.0 failed 4 times, most recent failure: Lost task 4.3 in stage 363.0 (TID 974) (<executor_ip> executor 3): java.lang.StackOverflowError at java.base/java.nio.ByteBuffer.position(ByteBuffer.java:1094) at java.base/java.nio.HeapByteBuffer.get(HeapByteBuffer.java:184) at org.apache.spark.util.ByteBufferInputStream.read(ByteBufferInputStream.scala:49) at java.base/java.io.ObjectInputStream$PeekInputStream.read(ObjectInputStream.java:2893) at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2909) at java.base/java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:3430) at java.base/java.io.ObjectInputStream.readHandle(ObjectInputStream.java:1801) at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1862) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2201) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447) at scala.collection.immutable.List$SerializationProxy.readObject(List.scala:527) at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447) at scala.collection.immutable.List$SerializationProxy.readObject(List.scala:527) at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447) at scala.collection.immutable.List$SerializationProxy.readObject(List.scala:527) at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447) at scala.collection.immutable.List$SerializationProxy.readObject(List.scala:527) at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at java.base/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1046) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2357) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2496) at java.base/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2390) at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2228) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1687) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:489) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:447) at scala.collection.immutable.List$SerializationProxy.readObject(List.scala:527) at jdk.internal.reflect.GeneratedMethodAccessor6.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
该异常来自TaskResultGetter线程,当前线程栈大小为1MB。
解决方法
- 调整TaskResultGetter线程栈大小:在Spark配置中设置
spark.driver.extraJavaOptions参数,增大线程栈容量,例如设置为-Xss4m(将栈大小调整为4MB),该参数针对Driver端生效,因为TaskResultGetter线程运行在Driver中。 - 优化序列化方式:替换默认的Java序列化为Kryo序列化,Spark配置添加
spark.serializer=org.apache.spark.serializer.KryoSerializer,Kryo对复杂嵌套结构的序列化/反序列化栈消耗更低,还可注册自定义类提升效率。 - 拆分任务结果:增加RDD/DataFrame的分区数,让单个Task处理的数据量减少,避免生成过大或嵌套过深的结果集合,降低反序列化时的栈压力。
- 重构数据结构:将代码中极深嵌套的Scala List结构改为扁平结构,或者用数组(Array)替代List,减少反序列化时的栈递归调用。
规避建议
- 优先使用DataFrame/Dataset:Spark对结构化数据的序列化有专门优化,相比RDD更不容易出现嵌套结构导致的栈溢出问题。
- 提前校验数据结构:在数据处理逻辑中避免生成多层嵌套的集合,尽量保持数据结构扁平化。
- 监控Driver线程状态:定期查看Driver的线程栈情况,重点关注TaskResultGetter这类处理任务结果的线程,提前发现栈溢出风险。
- 合理配置序列化参数:使用Kryo序列化时,可通过
spark.kryoserializer.buffer调整序列化缓冲区大小,适配大对象场景。
内容的提问来源于stack exchange,提问作者PRAVIN KUMAR
相关产品推荐
相关产品推荐

