Java 8 lambda的一个编译bug

最近利用github action向Maven中央仓库发布企业微信SDK时会失败,从日志中发现是系统资源耗尽了,日志如下:

php 复制代码
[INFO] Changes detected - recompiling the module! :dependency
[INFO] Compiling 35 source files with javac [debug target 8] to target/classes


The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
	at com.sun.tools.javac.tree.JCTree$JCLambda.accept(JCTree.java:1624)
	at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:576)
	at com.sun.tools.javac.comp.Attr.visitLambda(Attr.java:2435)
    ............

编译的环境是 Java 8

应该是递归引用导致OOM了,但是仔细REVIEW了代码并没有发现问题。困扰了一个多月。今天终于解决了,问题是由下面的代码引起的:

java 复制代码
public final class WecomUserAgent {
    /**
     * 版本号
     */
    public static final String VERSION = "1.2.4";
    /**
     * UserAgent
     */
    public static final String WECOM_USER_AGENT= "Wecom/" + VERSION + Optional.ofNullable(System.getProperty("java.version"))
            .map(javaVersion -> " Java/" + javaVersion)
            .orElse("");
 
    private WecomUserAgent() {
    }
}

根本的原因在于上面的静态变量WECOM_USER_AGENT

Java 8 中,被标记final 的静态属性初始化时如果在字符串拼接中使用了lambda流操作,可能导致javac递归,最终堆栈溢出。该问题在Java 9 得到了修复 Bug报告:bugs.openjdk.org/browse/JDK-...

解决方法

升级JDK

升级JDK到9+ 就可以直接解决这个问题。

兼容写法

如果无法直接升级JDK,可以使用静态块来初始化:

java 复制代码
public final class WecomUserAgent {
    /**
     * 版本号
     */
    public static final String VERSION = "1.2.4";
    /**
     * UserAgent
     */
    public static final String WECOM_USER_AGENT;

    static {
        WECOM_USER_AGENT = "Wecom/" + VERSION + Optional.ofNullable(System.getProperty("java.version"))
                .map(javaVersion -> " Java/" + javaVersion)
                .orElse("");
    }

    private WecomUserAgent() {
    }
}
相关推荐
꧁Q༒ོγ꧂4 分钟前
算法详解(二)--算法思想基础
java·数据结构·算法
次元工程师!6 分钟前
Sa-Token完成路由鉴权
java·服务器·前端
华如锦12 分钟前
一.2部署——大模型服务快速部署vLLM GPU 安装教程 (Linux)
java·linux·运维·人工智能·后端·python·vllm
小鸡脚来咯17 分钟前
设计模式,单例和工厂模式
java
Qiuner23 分钟前
Spring Boot 全局异常处理策略设计(三):@ExceptionHandler 与 @ControllerAdvice 生效原理源码解析
java·spring boot·后端
零度@24 分钟前
Java 消息中间件 - RabbitMQ 全解(保姆级 2026)
java·rabbitmq·java-rabbitmq
u01040583625 分钟前
企业微信自建应用权限模型与 RBAC 在 Spring Security 中的映射
java·spring·企业微信
墨雨晨曦8825 分钟前
通过调用deepseek的api来实现智能客服
java
予枫的编程笔记27 分钟前
Elasticsearch核心架构与基础原理:解密其极速性能的底层逻辑
java·大数据·人工智能·elasticsearch·搜索引擎·架构·全文检索