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() {
    }
}
相关推荐
一木 之林20 分钟前
五、C++新特性、关键字与编译原理
java·jvm·算法
han_hanker24 分钟前
新手公司项目实战
java·maven
vHelios30 分钟前
【电商项目】商品搜索开发复盘(3):搜索与封装实现逻辑思考与编写
java
AI人工智能+电脑小能手1 小时前
大白话说Java设计模式-37-中介者模式(源码剖析篇)
java·设计模式·线程池·中介者模式·源码分析·executor·applicationeventmulticaster
焦虑的说说1 小时前
虚拟线程浅析
java
摇滚侠1 小时前
《SpringBoot 3:入门与应用实战》第 7 章 AOP 思想与实现 阅读笔记 13
java·spring boot·笔记
Mr. zhihao1 小时前
线上卡顿排查决策手册:场景 × 命令 × 现象 × 调整方案
java·开发语言·jvm
FYKJ_20101 小时前
springboot网上购书商城---附源码15749
java·spring boot·后端·python·spark·django·php
LayZhangStrive2 小时前
Java IDEA - 各种快捷键设置汇总(提高工具使用效率)
java·idea·设置·快捷键