Domanda

Perché è il secondo pezzo di codice più veloce?

Map<Integer, Double> map = new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {
        map.put(i, j);
    }
}

Map<Integer, Double> map=new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {            
        map.put(new Integer(i), new Double(j));
    }
}
È stato utile?

Soluzione

autoboxing utilizza Integer.valueOf, che memorizza nella cache internamente oggetti Integer per i piccoli numeri interi (per default da -128 a 127, ma il valore massimo può essere configurato con la proprietà "java.lang.Integer.IntegerCache.high" - vedere il codice sorgente del Integer.valueOf), quindi è diverso dal chiamare direttamente new Integer. Perché Integer.valueOf fa un rapido controllo per la grandezza del valore intero prima di chiamare new Integer, è un po 'più veloce di chiamare new Integer direttamente (anche se usa più memoria se hai un sacco di piccoli numeri interi). Allocazione in Java è molto veloce, e il tempo facendo GC è proporzionale al numero di oggetti in tempo reale di breve durata (vale a dire non è proporzionale alla quantità di spazzatura), in modo da GC è anche molto veloce.

Ma a seconda della versione JVM e quali ottimizzazioni sono abilitati, v'è l'ottimizzazione di sostituzione scalare, che possono a produrre una differenza di prestazioni molto più grande in sede di assegnazione degli oggetti di breve durata (in tuo esempio che l'ottimizzazione non può essere fatto, perché si memorizzano gli oggetti in una mappa, ma in molte altre situazioni è utile).

Nelle versioni recenti JVM c'è ottimizzazione scalare la sostituzione ( tranne in 1.6.0_18 in cui l'analisi fuga è temporaneamente disabilitato ), il che significa che allocazioni di oggetti di breve durata possono essere ottimizzate via. Quando la sostituzione scalare in JVM era nuovo, qualcuno ha fatto un punto di riferimento dove c'era il codice simile al tuo. Il risultato è stato che il codice che ha usato primitive stato il più veloce, il codice con le chiamate new Integer() esplicite era quasi veloce come quella che utilizza primitive, e il codice che ha utilizzato autoboxing era molto più lento. Questo perché autoboxing utilizza Integer.valueOf e almeno allora ottimizzazione sostituzione scalare non ha preso quel caso particolare in considerazione. Non so se l'ottimizzazione è stata migliorata da allora.

Altri suggerimenti

Autoboxing utilizzerà Integer.valueOf e Double.valueOf. V'è un certo overhead nel chiamare questi metodi (anche se sarà alla fine ottenere inline). Anche Integer.valueOf fa qualche controllo per bassi valori di utilizzare le istanze messe in comune, che non è spesso una vittoria nel codice (anche se potrebbe ridurre la dimensione heap un po '). casi pool possono essere una vittoria in cui riducono dimensione heap, i tempi di GC e potrebbe anche migliorare le prestazioni test di uguaglianza ..

Ma, in generale, si tratta di un microoptimisation che si dovrebbe, in generale, ignorare.

A causa dei risultati di microbenchmarks sono inaffidabili?

Inoltre, auto-boxing è fatto usando Integer.valueOf () e Double.valueOf (), non i costruttori.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top