我们目前正在为我们的一款产品添加服务器端脚本功能。作为其中的一部分,我正在评估 JSR 223 脚本引擎。由于我们可能会在服务器上运行大量脚本,因此我特别关心这些脚本引擎的内存使用情况。将 Rhino(Apple JDK 1.6.0_65-b14-462-11M4609,Mac OS X 10.9.2)与 Nashorn(Oracle JDK 1.8.0-b132)进行比较,每个 ScriptEngine 实例的内存使用量似乎存在巨大差异。
为了测试这一点,我使用了一个简单的程序来启动 10 个空白 ScriptEngine 实例,然后阻止从标准输入读取。然后我使用 jmap 进行堆转储(jmap -dump:format=b,file=heap.bin),然后在转储中搜索相关的脚本引擎实例:
import javax.script.*;
public class test {
public static void main(String...args) throws Exception {
ScriptContext context = new SimpleScriptContext();
context.setWriter(null);
context.setErrorWriter(null);
context.setReader(null);
ScriptEngine js[] = new ScriptEngine[10];
for (int i = 0; i < 10; ++i) {
js[i] = new ScriptEngineManager().getEngineByName("javascript");
js[i].setContext(context);
System.out.println(js[i].getClass().toString());
}
System.in.read();
}
}
取消上下文中各种读取器/写入器字段的原因是因为我们不使用它们,并且早期的 Rhino 堆转储表明它们构成了每个实例开销的很大一部分(并且似乎没有共享) .
在 Eclipse MAT 中分析这些堆转储,然后我得到以下每个实例保留的堆大小:
- Rhino:13,472 字节/实例(如果我不将读取器/写入器字段清空,则上升到 73,832 字节/实例)
- Nashorn:324,408 字节/实例
Nashorn 的规模会增加 24 倍吗?执行速度不是我们将要执行的脚本(主要是 I/O 绑定)的主要关注点,因此我正在考虑发布我们自己的 Rhino 副本以在 Java 8+ 中使用。