2015-11-08 705 views
15

我有一個Java程序(使用JDK 7u80編譯),它大量使用了「JavaScript」ScriptEngine(JSR-223)。我注意到,與Java 7運行時環境(JRE 7u80)相比,我的程序在Java 8運行時環境(JRE 8u65)下執行時運行速度非常慢。Java 8 ScriptEngine與Java 7相比的主要性能問題

我已經把下面的SSCCE來說明問題,然後執行它的Java 7和Java 8在相同的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(); 
    } 
} 

中的JavaScript由一個IP地址轉換爲功能一個長,添加一個數字,然後將其轉換回IP地址 - 這是重複4096次。

我看到的Java 7和Java 8的結果如下:

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

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

我應該提出這個作爲與Java 8相關的性能缺陷?

UPDATED:包含預熱階段以確保所有代碼路徑在我的定時循環之前已經初始化。

+2

我無法重現您的結果,可能是因爲您沒有包含熱身階段。 – Tunaki

+0

這是如何重複一個沒有提到Java 7和Java 8之間性能差異的問題?這是一篇提到如何做微基準的文章。如果我正確地閱讀這篇文章,我應該做兩次循環,但只在第二次計時? – chrixm

+2

我建議你看看JMH做正確的基準。這是一個庫,它會自動包含一個預熱階段並避免測量錯誤的東西。你得到的差異可能只是因爲Nahsorn比Rhino需要更長的時間才能加載。 – Tunaki

回答

3

Java 8改進了JavaScript引擎,如果使用compile compiledScript方式,不要每次重新評估源代碼。使用eval方法,jdk8中使用的Hashorm引擎比jdk7中使用的Rhino更慢,但更安全。

不想一個StringBuffer Vs的字符串,以及用於Math.pow(2,32)和Math.pow常量的使用量(256,3)值如果尋找速度...

此致

+0

)感謝所有的意見和建議。我採用了兩種方法 - 第一種是'eval'腳本一次,然後在可能的地方使用'invokeFunction'。在由於用戶提供的JavaScript(我的用例是一個模塊化工具,用戶可以在塊中使用JavaScript)而無法實現的情況下,我採用了線程模塊使用X線程的固定線程池並行處理模板。 – chrixm