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() {
    }
}
相关推荐
Hx_Ma163 小时前
SpringMVC框架提供的转发和重定向
java·开发语言·servlet
期待のcode3 小时前
原子操作类LongAdder
java·开发语言
舟舟亢亢4 小时前
Java集合笔记总结
java·笔记
小酒窝.4 小时前
【多线程】多线程打印ABC
java
乡野码圣5 小时前
【RK3588 Android12】RCU机制
java·jvm·数据库
JAVA+C语言5 小时前
如何优化 Java 多主机通信的性能?
java·开发语言·php
编程彩机6 小时前
互联网大厂Java面试:从分布式架构到大数据场景解析
java·大数据·微服务·spark·kafka·分布式事务·分布式架构
小酒窝.6 小时前
【多线程】多线程打印1~100
java·多线程
君爱学习6 小时前
基于SpringBoot的选课调查系统
java
APIshop6 小时前
Java 实战:调用 item_search_tmall 按关键词搜索天猫商品
java·开发语言·数据库