Java 脚本引擎清除并处置
我的应用程序使用Java 脚本引擎清除并处置,java,nashorn,scriptengine,Java,Nashorn,Scriptengine,我的应用程序使用ScriptEngine为最终用户提供插件功能 ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine engine = engineManager.getEngineByName("nashorn"); 每当用户对其脚本进行更改时,应用程序就会用新实例替换引擎实例 String newScript = ...; engine = engineManager.getEngineByN
ScriptEngine
为最终用户提供插件功能
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
每当用户对其脚本进行更改时,应用程序就会用新实例替换引擎实例
String newScript = ...;
engine = engineManager.getEngineByName("nashorn");
engine.eval(newScript);
两个密切相关的问题:
- 我是否应该尝试重用引擎并对其执行某种
clear()
- 如果我只是用一个新实例替换引擎,我是否应该以某种方式处理以前的实例,以避免内存泄漏?(例如,我可以想象用户可以创建一个启动线程的脚本。)
问题是,我找不到任何类似于
clear()
或dispose()
的方法。这是否意味着我当前的方法是正确的?您可以使用单个引擎实例,但可以使用单独的绑定
对象<代码>绑定充当顶级程序环境,因此如果您想将脚本评估为基本上是“新的全局范围”,那么您可以这样做。查看javax.script
,了解如何做到这一点。您可以使用ScriptEngine.eval
作为第二个参数,或者使用ScriptContext
作为第二个参数
即使没有脚本代码从之前的评估中幸存下来,也可以节省一些初始化时间,因为脚本引擎已经预定义了各种JavaScript数据持有者类和属性映射(“隐藏类”)
还有:是的,所有东西都是垃圾收集的。不需要显式的“处理”API。我只想分享我自己测试的内容。这很有道理,但对于那些仍有疑问的人来说:如果只替换引擎实例,创建的线程确实会继续运行。:
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
String script =
"new java.lang.Thread(function() {\n" +
" for(;;) {" +
" print('Here\\'s Johnny !');" +
" java.lang.Thread.sleep(1000);" +
" }\n" +
"}).start();";
ScriptEngine engine = manager.getEngineByName("nashorn");
try {
engine.eval(script);
} catch (ScriptException e) {
e.printStackTrace();
}
// replace engine
engine = manager.getEngineByName("nashorn");
engine.eval("print('please, make it stop!!!');");
// please collect !!!
System.gc();
}
输出:
Here's Johnny !
please, make it stop!!!
Here's Johnny !
Here's Johnny !
Here's Johnny !
...
但您也可以使用类过滤器禁用特定类
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine((className) -> {
if ("java.lang.Thread".equals(className)) return false;
if ("java.lang.Runnable".equals(className)) return false;
if ("java.util.Timer".equals(className)) return false;
if (className.startsWith("java.util.concurrency")) return false;
if (className.startsWith("javafx")) return false;
if (className.startsWith("javax.swing")) return false;
if (className.startsWith("java.awt")) return false;
return true;
});
注意:一旦定义了
类过滤器
,反射类也会被自动阻止。因此,您不必显式地阻止这些包。一切都非常清楚,但是关于“无需处理”部分,请参见下面的回答:显然java不会为您清理正在运行的线程。
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine((className) -> {
if ("java.lang.Thread".equals(className)) return false;
if ("java.lang.Runnable".equals(className)) return false;
if ("java.util.Timer".equals(className)) return false;
if (className.startsWith("java.util.concurrency")) return false;
if (className.startsWith("javafx")) return false;
if (className.startsWith("javax.swing")) return false;
if (className.startsWith("java.awt")) return false;
return true;
});