2015-11-08 18 views
15

Ho un programma Java (compilato utilizzando JDK 7u80) che fa ampio uso di ScriptEngine "JavaScript" (JSR-223). Ho notato che il mio programma gira estremamente lentamente quando viene eseguito in un ambiente di runtime Java 8 (JRE 8u65) rispetto a un ambiente di runtime Java 7 (JRE 7u80).Problemi di prestazioni importanti con Java 8 ScriptEngine rispetto a Java 7

ho messo insieme il seguente SSCCE per dimostrare il problema e quindi eseguito sotto Java 7 e Java 8 sullo stesso PC di Windows:

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(); 
    } 
} 

Il JavaScript è costituito da una funzione che converte un indirizzo IP un lungo, aggiunge un numero e poi lo converte in un indirizzo IP - questo viene ripetuto 4096 volte.

sto vedendo i seguenti risultati tra Java e Java 7 8:

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

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

Dovrei alzando questo come un bug prestazioni associate con Java 8?

AGGIORNATO: Per includere una fase di riscaldamento per garantire che tutti i percorsi di codice siano stati inizializzati prima del ciclo di sincronizzazione.

+2

Non riesco a riprodurre i risultati, probabilmente perché non hai incluso una fase di riscaldamento. – Tunaki

+0

In che modo si tratta di un duplicato di una domanda che non menziona nulla sulle differenze di prestazioni tra Java 7 e Java 8? È un post che menziona come fare micro-benchmark. Se leggo correttamente quel post dovrei fare il ciclo due volte, ma solo cronometrarlo la seconda volta? – chrixm

+2

Ti suggerisco di esaminare JMH per fare benchmark corretti. È una libreria che includerà automaticamente una fase di riscaldamento ed eviterà di misurare la cosa sbagliata. La differenza che stai ottenendo potrebbe essere solo perché Nahsorn impiega più tempo a caricare di Rhino. – Tunaki

risposta

3

Java 8 migliora il motore JavaScript, se si utilizza la modalità compiledScript di compilazione, per non rivalutare il codice sorgente ogni volta. Con il metodo eval, il motore di Hashorm usato in jdk8 è più lento di Rhino usato in jdk7, ma più sicuro.

Preferisco uno StringBuffer vs una stringa, e l'utilizzo di costanti per Math.pow (2, 32) e Math.pow (256, 3) i valori, se si cerca di velocità ...

Distinti

+0

Grazie per tutti i commenti e i suggerimenti. Ho adottato un approccio a due punte: il primo è quello di 'eval' lo script una volta e poi usa 'invokeFunction' ove possibile.In aree in cui ciò non è possibile perché è un JavaScript fornito dall'utente (il mio caso d'uso è uno strumento di template in cui l'utente può usare JavaScript in blocchi), ho adottato un modulo di threading che utilizza un pool di thread fisso di thread X per elaborare modelli in parallelo. – chrixm