Jenkins执行mvn clean install时出现StackOverflowError求助
Spring Boot项目Jenkins构建报StackOverflowError问题排查
问题背景
我有一个Spring Boot制品,本地开发机通过Maven可正常构建,但在Jenkins服务器执行mvn clean install时触发StackOverflowError,这是唯一出现该错误的制品。添加参数-Xss2M增大栈空间可解决问题,但有两个疑问:
- 为什么开发机无需此设置?
- 增大栈空间是正确解决方案,还是仅隐藏了潜在问题(除架构重构缩短调用栈外)?
使用版本:
- Maven 3.8.7
- Java 21.0.10(也曾尝试Java 17)
堆栈跟踪
[INFO] Compiling 698 source files to /var/lib/jenkins/workspace/artifact/target/classes An exception has occurred in the compiler (21.0.10). Please file a bug against the Java compiler via the Java bug reporting page after checking the Bug Database for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you. java.lang.StackOverflowError at jdk.compiler/com.sun.tools.javac.code.Scope.includes(Scope.java:147) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readMethod(ClassReader.java:2618) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClass(ClassReader.java:2945) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClassBuffer(ClassReader.java:3036) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClassFile(ClassReader.java:3060) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.fillIn(ClassFinder.java:373) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:302) at jdk.compiler/com.sun.tools.javac.code.Symbol.complete(Symbol.java:683) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:1452) at jdk.compiler/com.sun.tools.javac.code.Type$ClassType.complete(Type.java:1203) at jdk.compiler/com.sun.tools.javac.code.Type$ClassType.getTypeArguments(Type.java:1129) at jdk.compiler/com.sun.tools.javac.code.Type$ClassType.allparams(Type.java:1151) at jdk.compiler/com.sun.tools.javac.code.Type$ClassType.isRaw(Type.java:1189) at jdk.compiler/com.sun.tools.javac.code.Types.capture(Types.java:4400) at jdk.compiler/com.sun.tools.javac.comp.InferenceContext.cachedCapture(InferenceContext.java:561) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2643) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1816) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:4409) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2581) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2626) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1816) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:4409) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2581) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2626) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1816) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:4409) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2581) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2626) ... at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1816) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:4409) at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2581) at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:662) at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2626)
问题解答
1. 为啥开发机不用设-Xss?
本地和Jenkins的JVM默认栈大小大概率不一样:
- JVM的默认栈空间(Xss)跟操作系统、JVM版本、硬件架构都有关系。比如Windows默认Xss一般比Linux大,64位JVM的默认值也可能和32位不同。要是你开发机用Windows,Jenkins跑在Linux服务器上,就容易出现这种差异。
- 本地构建时Maven默认会增量编译(没加clean的话),而Jenkins执行
clean install是从头编译所有698个文件,编译过程中编译器要处理更复杂的依赖链和类型推断,栈消耗自然更大。 - 开发机的IDE可能自动给JVM加了更大的栈空间参数,而Jenkins是纯命令行环境,用的是默认参数。
2. 增大栈空间是正确解法吗?会不会掩盖问题?
从堆栈跟踪看,错误出在Java编译器(javac)的类型推断和属性分析阶段,不是你的应用代码运行时出问题。这种情况分两种:
- 编译器本身的栈溢出bug:javac处理复杂泛型嵌套、超长链式调用或者深层继承时,可能因为递归过深爆栈。这种情况增大Xss是合理的临时解决办法,毕竟问题出在编译器实现,不是你的代码逻辑。
- 代码结构太复杂导致编译压力大:要是你代码里有极深的泛型嵌套、超长链式调用(比如
a.b.c.d.e.f.g()这种),或者复杂到离谱的继承体系,会让编译器的类型推断过程栈消耗剧增。这时候增大Xss能解决编译问题,但长期来看还是建议优化代码:- 把超长链式拆成几步,用临时变量存中间结果
- 简化泛型嵌套的层次
- 别搞过于复杂的继承关系
总结
- 加
-Xss2M是可行的解决方案,尤其是只在Jenkins全量编译时出问题,而且不影响应用运行的话,完全可以用。 - 要是想彻底解决,先排查代码里有没有特别复杂的编译单元(比如单个文件堆了一堆泛型或链式调用),针对性优化;也可以试试升级Maven或Java版本,新版本编译器可能已经修复了这类栈溢出的bug。
内容的提问来源于stack exchange,提问作者Vinc
相关产品推荐
相关产品推荐

