Major Performance Issues with Java 8 ScriptEngine

2019-03-18 03:27发布

问题:

I have a Java program (compiled using JDK 7u80) which makes extensive use of the "JavaScript" ScriptEngine (JSR-223). I have noticed that my program runs extremely slow when executed under a Java 8 runtime environment (JRE 8u65) in comparison to a Java 7 runtime environment (JRE 7u80).

I have put together the following SSCCE to demonstrate the problem and then executed it under Java 7 and Java 8 on the same Windows PC:

import javax.script.*;

public class SSCCE {
  public SSCCE() {
    ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine js = sem.getEngineByName("JavaScript");
    long t = 0;
    int i = 0;

    String gJs = "function ip2long(ip) {";
    gJs += "var aIP = ip.split(\".\");";
    gJs += "return (aIP[0] * Math.pow(256, 3)) + (aIP[1] * Math.pow(256, 2)) + (aIP[2] * 256) + (aIP[3] * 1);";
    gJs += "}";
    gJs += "function long2ip(l) {";
    gJs += "if (!isNaN(l) && ((l >= 0) || (l <= Math.pow(2, 32)))) {";
    gJs += "return Math.floor(l / Math.pow(256, 3)) + \".\" +";
    gJs += "Math.floor((l % Math.pow(256, 3)) / Math.pow(256, 2)) + \".\" +";
    gJs += "Math.floor(((l % Math.pow(256, 3)) % Math.pow(256, 2)) / Math.pow(256, 1)) + \".\" +";
    gJs += "Math.floor((((l % Math.pow(256, 3)) % Math.pow(256, 2)) % Math.pow(256, 1)) / Math.pow(256, 0));";
    gJs += "}";
    gJs += "return null;";
    gJs += "}";

    try {
      js.eval(gJs);
    }
    catch (Exception e) {
      e.printStackTrace();
    }

    System.out.println("Warming Up...");

    t = System.nanoTime();

    for (i = 0; i < 4097; i++) {
      try {
        String sJs = "var ip = \"192.0.2.0\";";
        sJs += "var nip = long2ip(ip2long(ip, " + i + "));";
        js.eval(sJs);
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }

    System.out.println("Starting...");

    t = System.nanoTime();

    for (i = 0; i < 4097; i++) {
      try {
        String sJs = "var ip = \"192.0.2.0\";";
        sJs += "var nip = long2ip(ip2long(ip, " + i + "));";
        js.eval(sJs);
      }
      catch (Exception e) {
        e.printStackTrace();
      }
    }

    System.out.println("Elapsed Time: " + (System.nanoTime() - t) / 1000000000.0f);
  }

  public static void main(String[] args) {
    new SSCCE();
  }
}

The JavaScript consists of a function which converts an IP address to a long, adds a number and then converts it to back an IP address - this is repeated 4096 times.

I am seeing the following results between Java 7 and Java 8:

D:\Scripts>java7 SSCCE
Warming Up...
Starting...
Elapsed Time: 0.5856594

D:\Scripts>java8 SSCCE
Warming Up...
Starting...
Elapsed Time: 4.6862915

Should I be raising this as a performance bug associated with Java 8?

UPDATED: To include a warm up phase to ensure all code paths have been initialized before my timing loop.

回答1:

Java 8 improve the JavaScript engine, if you use the compile compiledScript way, to not reevaluate the source code each time. With the eval method, Hashorm engine used in jdk8 is slower than Rhino used in jdk7, but more secure.

Prefer a StringBuffer vs a String , and usage of constants for Math.pow(2, 32) and Math.pow(256, 3) values if you looking for speed...

Yours