2013-02-28 14 views
25

La mia esperienza generale con Java 7 mi dice che è più veloce di Java 6. Tuttavia, ho trovato abbastanza informazioni che mi fanno pensare che non sia sempre così.Qual è la differenza tra Java 6 e 7 che potrebbe causare un problema di prestazioni?

Il primo bit di informazioni proviene da Minecraft trovato dati Snooper here. La mia intenzione era quella di guardare quei dati per determinare gli effetti delle diverse opzioni utilizzate per avviare Minecraft. Ad esempio volevo sapere se usare -Xmx4096m ha avuto un effetto negativo o positivo sulle prestazioni. Prima che potessi arrivare lì ho guardato la diversa versione di Java in uso. Copre tutto da 1,5 a uno sviluppatore usando 1.8. In generale man mano che aumenti la versione di java, vedi un aumento delle prestazioni dei fps. Attraverso le diverse versioni di 1.6 si vede anche questa tendenza graduale. Onestamente non mi aspettavo di vedere tante versioni diverse di java ancora in circolazione, ma immagino che le persone non eseguano gli aggiornamenti come dovrebbero.

Un po 'di tempo per le versioni successive di 1.6 si ottengono le più alte sbirciatine. 1.7 esegue circa 10 fps in media al di sotto delle versioni successive di 1.6 ma ancora superiore alle prime versioni di 1.6. Su un campione del mio sistema è quasi impossibile vedere la differenza, ma guardando il campione più ampio è chiaro.

Controllare per la possibilità che qualcuno possa aver trovato un interruttore magico per Java con cui ho controllato solo guardando i dati senza passare alcun passaggio. In questo modo avrei avuto un controllo ragionevole prima di iniziare a guardare le diverse bandiere.

Ho ignorato la maggior parte di ciò che stavo vedendo in quanto potrebbe trattarsi di Magic Java 6 che qualcuno non condivide solo con me.

Ora sto lavorando a un altro progetto che richiede il passaggio di un array in un InputStream per essere elaborato da un'altra API. Inizialmente ho usato un ByteArrayInputStream perché avrebbe funzionato senza problemi. Quando ho visto il codice, ho notato che ogni funzione era sincronizzata. Poiché non era necessario per questo progetto, ho riscritto uno con la sincronizzazione rimossa. Ho quindi deciso che volevo sapere qual era il costo generale della sincronizzazione per me in questa situazione.

Ho preso in giro un semplice test solo per vedere. Ho cronometrato tutto con System.nanoTime() e ho usato Java 1.6_20 x86 e 1.7.0-b147 AMD64 e 1.7_15 AMD64 e usando il -server. Mi aspettavo che la versione AMD64 potesse sovraperformare solo in base all'architettura e avere tutti i vantaggi di java 7. Ho anche guardato il 25 °, 50 ° e 75 ° percentile (blu, rosso, verde). Comunque 1.6 con no-server battere i pantaloni fuori da ogni altra configurazione. graph

Quindi la mia domanda è. Che cosa c'è nell'opzione 1.6 -server che sta influenzando le prestazioni che è anche impostato per default su on in 1.7?

So che la maggior parte del miglioramento della velocità in 1.7 è venuto dal default alcune delle opzioni di prestazioni più radicali in 1,6 a on, ma uno di loro sta causando una differenza di prestazioni. Io non so quali guardare.

public class ByteInputStream extends InputStream { 

public static void main(String args[]) throws IOException { 
    String song = "This is the song that never ends"; 
    byte[] data = song.getBytes(); 
    byte[] read = new byte[data.length]; 
    ByteArrayInputStream bais = new ByteArrayInputStream(data); 
    ByteInputStream bis = new ByteInputStream(data); 

    long startTime, endTime; 

    for (int i = 0; i < 10; i++) { 
     /*code for ByteInputStream*/ 
     /* 
     startTime = System.nanoTime(); 
     for (int ctr = 0; ctr < 1000; ctr++) { 
      bis.mark(0); 
      bis.read(read); 
      bis.reset(); 
     } 
     endTime = System.nanoTime(); 

     System.out.println(endTime - startTime); 
     */ 

     /*code for ByteArrayInputStream*/ 
     startTime = System.nanoTime(); 
     for (int ctr = 0; ctr < 1000; ctr++) { 
      bais.mark(0); 
      bais.read(read); 
      bais.reset(); 
     } 
     endTime = System.nanoTime(); 

     System.out.println(endTime - startTime); 
    } 

} 

private final byte[] array; 
private int pos; 
private int min; 
private int max; 
private int mark; 

public ByteInputStream(byte[] array) { 
    this(array, 0, array.length); 
} 

public ByteInputStream(byte[] array, int offset, int length) { 
    min = offset; 
    max = offset + length; 
    this.array = array; 
    pos = offset; 
} 

@Override 
public int available() { 
    return max - pos; 
} 

@Override 
public boolean markSupported() { 
    return true; 
} 

@Override 
public void mark(int limit) { 
    mark = pos; 
} 

@Override 
public void reset() { 
    pos = mark; 
} 

@Override 
public long skip(long n) { 
    pos += n; 
    if (pos > max) { 
     pos = max; 
    } 
    return pos; 
} 

@Override 
public int read() throws IOException { 
    if (pos >= max) { 
     return -1; 
    } 
    return array[pos++] & 0xFF; 
} 

@Override 
public int read(byte b[], int off, int len) { 
    if (pos >= max) { 
     return -1; 
    } 
    if (pos + len > max) { 
     len = max - pos; 
    } 
    if (len <= 0) { 
     return 0; 
    } 
    System.arraycopy(array, pos, b, off, len); 
    pos += len; 
    return len; 
} 

@Override 
public void close() throws IOException { 
} 

}// end class 
+8

+1 per un bel grafico e domanda ben documentata. –

+9

Ho l'opinione opposta. C'è un sacco di verbosità qui, e un bel grafico, ma nessun vero contenuto. Se avessi appena mostrato il tuo codice e descritto i risultati in una tabella, più persone sarebbero in grado di aiutarti. Così com'è, tutto quello che è probabile che tu possa ottenere è supposizioni. -1 se potessi. – parsifal

+0

Cosa c'è sull'asse Y? Hai misurato più compiti ripetuti, non uno solo? Sei sicuro che il GC non si intrometta nei risultati? – Dariusz

risposta

5

penso, come gli altri hanno da dire, che i test sono troppo brevi per vedere le questioni fondamentali - il grafico sta mostrando nanoTime, e che implica la sezione centrale essendo completa l'misurate in 0,0001 a 0.0006s.

Discussione

La differenza fondamentale in -server e -client è che -server aspetta la JVM di essere in giro per molto tempo e spende quindi lo sforzo nella fase iniziale per ottenere migliori risultati a lungo termine.-client mira a tempi di avvio rapidi e prestazioni abbastanza buone.

In particolare, l'hotspot viene eseguito con più ottimizzazioni e richiede più CPU per l'esecuzione. In altre parole, con -server, potresti notare che il costo dell'ottimizzatore supera qualsiasi guadagno dall'ottimizzazione.

Vedi Real differences between "java -server" and "java -client"?

In alternativa, si può anche essere visto gli effetti di tiered compilation dove, in Java 7, hotspot non calci in così in fretta. Con solo 1000 iterazioni, l'ottimizzazione completa del codice non verrà eseguita fino a tardi e i benefici saranno quindi minori.

È possibile ottenere informazioni dettagliate se si esegue java con l'opzione -Xprof, la JVM scaricherà alcuni dati sul tempo trascorso in vari metodi, sia interpretati che compilati. . Si dovrebbe dare un'idea di ciò che è stato compilato, e il rapporto tra (CPU) tempo prima hotspot preso a calci in

Tuttavia, per ottenere un quadro veritiero, si ha realmente bisogno di eseguire questo molto più lunghi - secondi minuti , non millisecondi: per consentire a Java e al sistema operativo di riscaldarsi. Sarebbe anche meglio effettuare il ciclo del test in main (in modo da avere un loop contenente il loop di test principale strumentato) in modo da poter ignorare il riscaldamento.

EDIT secondo cambiato in minuti per garantire che hotspot, la JVM e il sistema operativo sono propriamente 'riscaldato'

+0

e se si desidera misurare alcune prestazioni di runtime di alcune app specifiche, spesso quelle eseguite per ore ... e le app Web eseguite 24/7. A volte stressato con carico, a volte no. Questo è il caso d'uso rilevante, non ciò che accade nei primi millisecondi o secondi. – eis

+0

@eis: ti sento. Qui, abbiamo una sezione molto piccola di codice per il profilo (piuttosto che un'app Web) con un solo percorso di codice attraverso (a differenza di qualsiasi codice reale), ed è vincolata alla CPU (piuttosto che avere effetti I/O), quindi le ore potrebbero essere overkill * in questo caso *. Sono in completa concordanza con te su una scala milliseconda. –

Problemi correlati