Java8で帳票クリエータを実行すると遅いのはNashornが遅いから
こんにちは、開発担当の Masa です。
これまで何回か Nashorn 関連の話題を出しましたが、「シーオーリポーツ 帳票クリエータ Ver.3 for Java」は Lot_012 で無事 Java8 に対応することができました・・・が、Java7 と比べて実行速度が遅いことが発覚しました。
Java8 自体は Java7 よりも速いはずなのに何故!?というわけで、調べてみると原因は Nashorn でした。
まずは動かぬ証拠を。
簡単なスクリプトを追加した帳票を3ページ出力する処理を、Java7、Java8、Java8 + Rhino で実行しました。
Java8(Nashorn)は遅いですね。比べて Java8 + Rhino は速いです。
※Java8 + Rhino の環境構築については前々回を参照
Rhino | Nashorn | |
---|---|---|
Java7 | 1,721ms | - |
Java8 | 1,325ms | 2,909ms |
Nashorn は"関数定義が異常に遅いが実行速度は高速"らしいのですが、組み込み関数を入れても 10 回に満たない関数定義でそこまで差が出るとは思えず。
Java VisualVM で調べてみました。
3ページだと差が分かりにくいので、"スクリプト内での関数定義無し"で 100ページ出力するプログラムをサンプリング。
Java7(Rhino)はこう。
※JOPtion~は関係ないので無視してください
帳票クリエータの処理だけを合計すると、1,299ms 。
ホット・スポットを見ると、eval に 299ms かかってますね。許容できる範囲ですけども。
さて、お待ちかねの Java8(Nashorn)!!
※JOPtion~は関係ないので無視してください
帳票クリエータの処理だけを合計すると、衝撃の 14,299ms 。桁が違います。
ホット・スポットを見ると、java.lang.Class.forName() だけで 12,495ms。嫌な予感しかしません。
詳細を見ると、グローバルスコープにオブジェクトを設定している箇所で 10,205ms。
というか、eval も 2,392ms ですけど(ScriptManager.eval の中は nashorn の eval です)。
もっと詳細をドン!
居ましたね。java.lang.Class.forName()。
しかもこれ、remove です。もちろん put でも同様に java.lang.Class.forName()。
グローバルスコープにオブジェクトを追加/削除した時点で該当のクラスをロードしてるように見えます。
何でしょう、コレ。
全部使うとは限らないし、せめて最初に使用する時にしてくれないでしょうか。。。あと remove でロードはやめて欲しい(切実)。
当分 Java8 + Rhino で実行するのが良さそうです。