Stavo cercando di vedere la differenza di prestazioni tra la pre-inizializzazione di un ArrayList
a una determinata capacità, l'andare con la capacità predefinita e l'espansione su richiesta. Solo per curiosità. Ho scoperto che il codice array di capacità predefinito è ~ 10% FASTER rispetto al codice che inizializza la matrice alla capacità richiesta. Ecco il codice che ho usato:Prestazioni di ArrayList
public class Test {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
for(int j=0;j<10;++j) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<1000000;++i) {
list.add(i);
}
}
long t2 = System.currentTimeMillis();
System.out.println("Time taken: " + (t2-t1)/10.0);
}
}
ho sempre ottengo ~ 77 ms per questa versione sulla mia macchina, mentre io ottengo ~ 85 ms se cambio l'inizializzazione List per new ArrayList<Integer>(1000000)
. Perché è così? Non dovrebbe essere il contrario? In effetti, la lista senza pre-init è costantemente un bit minimo (~ 0,5-1 ms) più veloce rispetto all'utilizzo di Integer[]
. Fondamentalmente, quello che dice è default capacity arraylist > simple array > pre-capacity-ensured arraylist
in prestazioni di inserimento.
Questo è molto strano per me. La mia ipotesi iniziale è che abbia qualcosa a che fare con l'allocazione della memoria, qualcosa come dare 1000000 blocchi int in una volta sola è forse più lento di ottenere lentamente più spazio? È riproducibile anche su altre macchine? Sto usando jdk 1.6.0, Mac OS X, usando eclipse.
ho provato in altri due ambienti: -> provato a fare funzionare java + javac da linea di comando, invece di Eclipse - Qui ho pre-capacity-ensured arraylist > simple array > default capacity arraylist
, in modo coerente.
-> Ho provato a eseguire java + javac sul mio desktop Linux (RHEL). Questa scatola ha 24 GB di RAM, mentre il mio portatile aveva solo 8 GB. Qui ottengo plain array >>> default capacity arraylist > pre-capacity-ensured arraylist
. La matrice semplice è super veloce, circa 2-3 volte più veloce in questo caso rispetto agli altri due.
EDIT: Seguendo @ suggerimento di JonSkeet nei commenti, ho usato nanoTime()
e Integer
invece di int
. Non si tratta ancora del problema che il riscaldamento JIT non viene preso in considerazione. Dopo queste modifiche, vedo costantemente che la matrice semplice è la più veloce in tutti i test. Ma la lista di capacità garantita è ancora più lenta di circa il 5-10% rispetto alla lista di capacità di default per me in tutti e 3 gli ambienti sopra. MA alcuni utenti sembrano avere il comportamento corretto, quindi questo potrebbe essere un caso molto specifico.
EDIT2: Se uso String anziché intero come elemento, il comportamento è corretto (plain array > pre-capacity-ensured arraylist > default capacity array
). Quindi penso che l'autoboxing sia in realtà il colpevole.
per cominciare, questo è * non * un buon modo di benchmarking. Stai includendo il tempo di riscaldamento JIT e stai usando 'currentTimeMillis' invece di' nanoTime'. Prova con https://code.google.com/p/caliper/ - Inoltre, sospetto che gran parte del tempo del tuo test venga speso per racimolare un milione di valori int. Prova a utilizzare qualcosa in cui * non * è necessario creare un nuovo oggetto per ogni iterazione. –
Solo un consiglio utile: esegui il test due volte e osserva i risultati della seconda analisi. La prima esecuzione è spesso macchiata a causa del caricamento su richiesta della VM. – Kylar
Ho cambiato il ciclo esterno per eseguire 100 iterazioni e ho trovato che la versione preliminare era all'incirca due volte più veloce. –