9

現在、サーバー側のスクリプト機能を製品の 1 つに追加する作業を進めています。その一環として、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 インスタンスを起動し、stdin からの読み取りをブロックする単純なプログラムを使用します。次に、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 バイト/インスタンス (リーダー/ライター フィールドを null にしないと、最大 73,832 バイト/インスタンスになります)
  • Nashorn: 324,408 バイト/インスタンス

この 24 倍のサイズの Nashorn の増加は予想されますか? 実行速度は、実行するスクリプト (ほとんどが I/O バウンド) にとって大きな問題ではないため、Java 8+ で使用する独自の Rhino のコピーを出荷することを検討しています。

4

1 に答える 1

0

ナッソーンとは?

Nashorn は、Java 8 でリリースされた JVM 用の JavaScript エンジンです。Nashorn は、組み込みの JavaScript インタープリターとコマンドライン ツールで構成されています。Nashorn の目的は、ネイティブ JVM を使用して Java で高パフォーマンスの JavaScript ランタイムを実装することです。Nashorn を使用すると、開発者は JavaScript を Java アプリケーションに組み込み、JavaScript コードから Java メソッドとクラスを呼び出して、2 つの言語間のシームレスな統合を実現できます。

メモリ消費量が多いのはなぜですか?

Nashorn オブジェクトとプロパティ マップは現在、多くのプロパティに対応していません。PropertyMap を不変にする理由は、PropertyMap 参照を比較することによってインライン呼び出しサイトを迅速に検証できるようにするためです。これにより、Nashorn でのメモリ消費が高くなります。

1 つの解決策は、 pre-script-java-functionsに切り替えることです。Java サーバーには特定のタスク用の Java 関数があり、Nashorn エンジンからその関数を呼び出すと、オブジェクト マッピングが作成されず、すべてが作成されるためです。 Javaで関数を実行するだけで結果が得られるため、JS関数を使用してJavaですべてをマップするのではなく、メモリ消費量が比較的少なくなります。これらの種類の pre-script-java-functions は、WSO2-Identity Server アダプティブ スクリプト機能で使用されます。これは、Nashorn で大量のメモリ割り当てとメモリ消費を処理する 1 つの方法です。

于 2021-07-30T04:56:24.443 に答える