使用 Java 11 的独立 Nashorn 在 eval 时抛出 java.lang.StackOverflowError

2023-12-31

我遇到了 Nashorn 的一个问题,当评估一个大表达式时,它在 Java 8 中工作正常,但抛出一个java.lang.StackOverflowError在Java 11中。


    Exception in thread "main" java.lang.StackOverflowError
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:444)
        at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterJoinPredecessorExpression(LocalVariableTypesCalculator.java:777)
        at org.openjdk.nashorn.internal.ir.JoinPredecessorExpression.accept(JoinPredecessorExpression.java:114)
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.visitExpression(LocalVariableTypesCalculator.java:603)
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:447)
        at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)

我碰到这个问题 https://stackoverflow.com/questions/69812339/js-script-doesnt-run-with-java-11-but-works-with-java-8,并尝试解决此问题,如建议的那样这条评论 https://stackoverflow.com/a/69825990/7518719,我尝试将独立 Nashorn 与 Java 11 一起使用,方法是使用org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory在我的代码中(参见这一页 https://github.com/szegedi/nashorn/wiki/Using-Nashorn-with-different-Java-versions#using-nashorn-on-java-11-to-14有关“为什么我们需要这样做”的信息)。

我有一个简单的 Maven 项目,我已将以下内容添加到我的 pom.xml 中:为简单起见,我仅包含以下重要部分:

  • 纳肖恩依赖
  • Maven 编译器插件

     <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
        
            <groupId>org.example</groupId>
            <artifactId>maven-project</artifactId>
            <version>1.0-SNAPSHOT</version>
            <packaging>jar</packaging>
        
            <dependencies>
                <dependency>
                    <groupId>org.openjdk.nashorn</groupId>
                    <artifactId>nashorn-core</artifactId>
                    <version>15.3</version>
                </dependency>
            </dependencies>
        
            <build>
                <plugins>
                    ...
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.8.0</version>
                        <configuration>
                            <release>11</release>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        
        </project>

(除了这些,我正在使用maven-dependency-plugin and maven-jar-plugin将其捆绑到可执行 Jar 中)。

以下是我的Java代码: 主程序.java

    package main;
    
    import org.openjdk.nashorn.api.scripting.NashornScriptEngine;
    import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
    
    import javax.script.ScriptEngine;
    
    public class Main {
    
        public static void main(String[] args) {
            // write your code here
            String expression = "(\"BUY\" == \"BUY\") && (\"BUY\" == \"BUY\") && (1.00 >= 1000.000)"; // It's a long expression which contains conditions like this.
    
            try {
                NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
                System.out.println("================================================================================");
                System.out.println("factory.engineName: " + factory.getEngineName());
                System.out.println("factory.engineVersion: " + factory.getEngineVersion());
                System.out.println("factory.languageName: " + factory.getLanguageName());
                System.out.println("factory.languageVersion: " + factory.getLanguageVersion());
                System.out.println("================================================================================");
                ScriptEngine engine = factory.getScriptEngine();
    
                Object results = engine.eval(expression);
                System.out.println("Successful");
    
                System.out.println(results);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 

带有Java版本java 版本“11.0.9”2020-10-20 LTS,我正在编译一个名为maven-project-1.0-SNAPSHOT.jar通过做mvn clean install.

运行Jar的主类时如下:


    java -jar target/maven-project-1.0-SNAPSHOT.jar

基于此信息 https://github.com/szegedi/nashorn/wiki/Using-Nashorn-with-different-Java-versions#using-nashorn-on-java-11-to-14,独立版本的 Nashorn 将加载 Java 11,因为我已经使用了org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory,因此,我不期望java.lang.StackOverflowError使用 Java 11。

但我的输出产生了 StackOverflowError:

    ================================================================================
    factory.engineName: OpenJDK Nashorn
    factory.engineVersion: 15.3
    factory.languageName: ECMAScript
    factory.languageVersion: ECMA - 262 Edition 5.1
    ================================================================================
    Exception in thread "main" java.lang.StackOverflowError
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterJoinPredecessorExpression(LocalVariableTypesCalculator.java:775)
        at org.openjdk.nashorn.internal.ir.JoinPredecessorExpression.accept(JoinPredecessorExpression.java:114)
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.visitExpression(LocalVariableTypesCalculator.java:603)
        at org.openjdk.nashorn.internal.codegen.LocalVariableTypesCalculator.enterBinaryNode(LocalVariableTypesCalculator.java:447)
        at org.openjdk.nashorn.internal.ir.BinaryNode.accept(BinaryNode.java:329)



Update:当编译这个时Java 17和测试,我没有收到 StackOverflowError。正如@Thorbjørn Ravn Andersen 所指出的 在评论中,检查这一点的原因是为了排除在 Java 11 中选择内置 Nashorn 而不是独立 Nashorn 的可能性。 (自从Java 17没有内置的 Nashorn,它只会选择独立的 Nashorn)。

基于此,我还可以想到对这个问题的补充:

我们如何确保独立的 Nashorn 被选中Java 11?

我尝试按如下方式执行jar(参考这个答案 https://stackoverflow.com/a/65267832/7518719 of 这个相关问题 https://stackoverflow.com/questions/65267831/intellij-put-some-dependencies-on-the-module-path-in-non-modular-application),但仍然抛出 StackOverflowError。 (这/path/to/my/maven-project/target/libs/目录包含诸如nashorn-core-15.3.jar, asm-7.3.1.jar, asm-commons-7.3.1.jar ...)

java --module-path "/path/to/my/maven-project/target/libs/" --add-modules org.openjdk.nashorn -jar target/maven-project-1.0-SNAPSHOT.jar

(不是像这样传递参数/标志,更好的方法是将它们添加为诗歌中的配置等 - 并“更整洁”地处理它)。


仅供参考,以下代码可以很好地使用Java 8,但抛出相同的 StackOverflowErrorJava 11,这就是为什么我必须使用org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory代替javax.script.ScriptEngineManager.


    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;
    import javax.script.ScriptException;
    
    public class Main {
    
        public ScriptEngine engine = new ScriptEngineManager().getEngineByName(ENGINE_NAME);;
        public static final String ENGINE_NAME = "nashorn";
    
        public static void main(String[] args) {
            // write your code here
            Main main = new Main();
            Object result = null;
            String exp = "(1640 >= 10) && (1640 <= 100) && (1640 >= 123)";
            try {
                result = main.engine.eval(exp);
                System.out.println(result);
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
    }

我在这里错过了什么吗?预先感谢您提供任何解决方案。


JavaScript 代码中导致此问题的实际源代码表达式有多长?

在 Java 8 中不会出现异常,因为 Java 8 中的 Nashorn 没有一些更高级的静态类型推断功能,这些功能使其能够在证明某些变量始终是整数或双精度数而不是对象时生成更优化的代码。

这种静态类型推断是在后来的 Nashorn 版本中添加的,该版本是随 Java 9 一起发布的。堆栈溢出发生在其代码中,因为它需要递归地遍历表达式树。如果你有一个极其长表达,这可能会发生。我建议您将很长的表达式分解为较小的表达式,要么将它们隔离到局部函数中,要么将它们分配给局部变量。局部函数更好,因为这样您可以保持短路评估,例如如果你有

function f(a, b, c, d, e, f, g, h) {
  return a == b && c == d && e == f && g == h;
}

你可以这样做

function f(a, b, c, d, e, f, g, h) {
  function p1() {
    return a == b && c == d;
  }
  function p2() {
    return e == f && g == h;
  }
 
  return p1() && p2();
}

这个示例只是说明了该技术,Nashorn 应该能够在遇到堆栈溢出之前评估很长的表达式。


或者,使用显式运行 JVM-Xss设置为线程提供更多堆栈内存。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Java 11 的独立 Nashorn 在 eval 时抛出 java.lang.StackOverflowError 的相关文章

随机推荐

  • 如何存储每个类别对象的总提款金额?

    我有一个Category类 并且该类的每个实例都有一个分类帐属性 该分类帐属性实际上是一个字典列表 其中包含以下形式的取款和存款金额以及描述 amount amount description description 现在 我想定义一个函数
  • 在 Blend 2015 中使用 3D OBJ 文件

    我刚刚开始学习 WPF 3D 并按照教程进行操作 我创建了一个 3D 模型并将其导出为 OBJ 文件 创建一个新的 WPF 项目并添加此 OBJ 文件 我如何在里面使用它Window or Viewport3D 我在 Microsoft 找
  • 便携式图书馆的语言选择

    我想编写一个库 它将与在 Windows Linux 和 OS X 等现代操作系统上运行的其他程序动态链接 即 它将部署为 dll or so模块 在这种情况下最合适的语言是什么 我应该坚持使用纯 C 吗 或者C 也可以吗 您可以使用 C
  • std::lower_bound 和 std::set::lower_bound 之间的差异

    C 草案谈到了 std lower bound 25 4 3 1 lower bound lower bound template
  • 可以在沙箱中运行的 Mini-OSGi(如 AppEngine 或 WebStart)?

    我真的很喜欢 OSGi 实现的模块化捆绑包的概念 我还喜欢 托管部署 服务 例如 Google AppEngine 用于 Web 应用程序 或 Java WebStart 用于客户端软件 这两个想法似乎在概念上很好地互补 然而 OSGi 标
  • 对 Primefaces 中的树节点进行排序

    我正在使用 JSF 2 1 和 Primefaces 3 3 我正在使用 primefaces 树组件从数据库中创建树 我想按字母顺序对各级树节点进行排序 请帮我解决这个问题 我们在排序时遇到了问题Comparator并发现 有一个方便的P
  • 反序列化 XML 时忽略指定的编码

    我正在尝试通过套接字读取从外部接口接收到的一些 XML 问题是 XML 标头中指定的编码错误 显示为 iso 8859 1 但实际上是 utf 16BE 据记录编码是utf 16BE 但显然他们忘记设置正确的编码 为了在反序列化时忽略编码
  • Node.js HTTP 客户端中的自动 UTF-8 编码

    我尝试使用 Node js 从远程主机加载 XML 内容 问题是像 这样的德语 元音变音 被破坏了 就像在浏览器中一样 这通常是一个简单的编码问题 但由于远程主机上的 XML 内容是用 iso 8859 2 编码的 所以我没有成功让这些字母
  • 消息:插入动态输入字段数据时未初始化的字符串偏移量:0

    我正在使用 CodeIgniter 我得到了动态选择框 从第二个选择框中 用户可以选择状态并根据状态输入字段进行显示 检查下面的屏幕截图 如果用户单击Add More然后将显示下面的选择框 现在从第二个选择框中 我选择Status one因
  • 如何使用 Symfony 表达式语言在 @Security 注释中使用类常量?

    我正在使用 Symfony 3 并且创建了一个自定义 Voter 类 我想使用访问它SensioFrameworkExtraBundle https symfony com doc current bundles SensioFramewo
  • 对重载new和delete施加限制

    是否可以对重载运算符 new 和 delete 施加一些限制 我的重载 new 在另一个文件中链接到我的测试程序 场景是 if condition is satisfied call overloaded new else call the
  • 如何在android中卸载应用程序时清除数据库

    我使用数据库来存储消息 如果我卸载我的应用程序并再次重新安装相同的应用程序 数据库保持不变 但我想清除我的数据库 如何解决这个问题 要监听卸载事件 您必须实现收到的广播 例如
  • 在条件表达式中声明变量(三元运算符)

    是否可以在条件表达式中声明变量 例如 下面的代码返回语法错误 因为我已经在条件表达式中声明了变量 x var a document getElementById userData var d a value function d lengt
  • 在 Vue.js 中构建期间传递要由 .env.[mode] 文件使用的参数(命令行)

    Goal 传递一个在构建时使用的参数 以便能够在我的 env Production 文件中使用它 或者如果不可能的话 可以让我将它用作环境变量 env 生产文件 VUE APP CLIENT ID 00 should be using wh
  • 计算一行中 NULL 属性的数量

    我想在表中添加一个新列来记录每个元组 行 值为空的属性的数量 如何使用 SQL 获取号码 例如 如果一个元组是这样的 Name Age Sex Blice 100 null 我想更新元组如下 Name Age Sex nNULL Blice
  • EclipseLink 审核/历史记录/跟踪更改

    我尝试实现一种跟踪数据更改并为我的应用程序创建历史日志的方法 因为我正在使用 EclipseLink 所以应该很容易并且可以像它们一样获得更改写在 EclipseLink FAQ 上 http wiki eclipse org Eclips
  • 数组作为类的私有成员

    我正在尝试创建一个具有私有成员 数组 的类 我不知道数组的大小 直到将值传递到构造函数中才知道 定义类构造函数以及 h 文件中的定义以允许数组大小可变的最佳方法是什么 如果你想要一个 真正的 C 风格数组 你必须向你的类添加一个指针私有成员
  • 为什么此代码在 Xcode 模拟器上有效,但在设备上不起作用?

    我真的希望有人向我解释一下 我正在编写一个使用其设备 MAC 地址的应用程序 并且此代码在模拟器上完美运行 但在设备上不起作用 我从问题中得到了这个代码在 Objective C 中获取路由器 mac 无需系统调用 ARP https st
  • 有效的重新排序 - 根据新的 JMM

    我只是想知道以下重新排序在新的 JMM 模型下是否有效 Original Code instanceVar1 value normal read operation no volatile synchronized this instanc
  • 使用 Java 11 的独立 Nashorn 在 eval 时抛出 java.lang.StackOverflowError

    我遇到了 Nashorn 的一个问题 当评估一个大表达式时 它在 Java 8 中工作正常 但抛出一个java lang StackOverflowError在Java 11中 Exception in thread main java l