2015-07-14 12 views
44

Ho provato a creare la mia mappa per aumentare le prestazioni per un ambiente speciale e ho realizzato qualcosa di molto interessante: la creazione di uno new Hashmap<Integer,String>(2000) è più veloce di new Object[2000] - non importa in quale ordine eseguo questi comandi. Questo è abbastanza confuso per me, esp. perché il costruttore di hashmap contiene un table = new Entry[capacity], in base a this. C'è qualcosa di sbagliato nel mio banco di prova?Perché la creazione di una HashMap è più veloce della creazione di un oggetto []?

public static void test(int amm){ //amm=1_000_000 
    Map<Integer,String> m1 = null; 
    Object[] arr = null; 

    long time = System.nanoTime(); 
    for(int i = 0; i < amm; i++){ 
     m1 = new HashMap<Integer, String>(2000); 
    } 
    System.out.println("m1: " + (System.nanoTime() - time)); //m1: 70_455_065 

    time = System.nanoTime(); 
    for(int i = 0; i < amm; i++){ 
     arr = new Object[2000]; 
    } 
    System.out.println("arr: " + (System.nanoTime() - time)); //arr: 1_322_473_803 
} 

Mi piacerebbe vedere i risultati dei test su un altro computer. Non ho idea del perché la creazione di un HashMap è 10 volte più veloce rispetto alla creazione di un Object[].

+0

Dipende dall'implementazione JDK. Quale JDK e versione stai usando per eseguire questo test? – BladeCoder

+0

@BladeCoder Sto usando 1.7.0_79 (IceTea 2.5.5) (7u79-2.5.5-0ubuntu0.14.04.2) e mi riferisco a java.version. –

+4

Infatti, in una versione chiusa di OpenJDK 1.7, nessun array è inizializzato nel costruttore di HashMap (è fatto al primo inserimento) che spiega il divario di velocità: http://grepcode.com/file_/repository.grepcode.com/java/ root/jdk/openjdk/7u40-b43/java/util/HashMap.java /? v = source – BladeCoder

risposta

51

Se si guarda l'attuazione HashMap, il costruttore si presenta come:

public HashMap(int initialCapacity, float loadFactor) { 
    if (initialCapacity < 0) 
     throw new IllegalArgumentException("Illegal initial capacity: " + 
              initialCapacity); 
    if (initialCapacity > MAXIMUM_CAPACITY) 
     initialCapacity = MAXIMUM_CAPACITY; 
    if (loadFactor <= 0 || Float.isNaN(loadFactor)) 
     throw new IllegalArgumentException("Illegal load factor: " + 
              loadFactor); 

    this.loadFactor = loadFactor; 
    threshold = initialCapacity; 
    init(); 
} 

E init() assomiglia:

/** 
* Initialization hook for subclasses. This method is called 
* in all constructors and pseudo-constructors (clone, readObject) 
* after HashMap has been initialized but before any entries have 
* been inserted. (In the absence of this method, readObject would 
* require explicit knowledge of subclasses.) 
*/ 
void init() { 
} 

Quindi initialCapacity realtà non abituarsi a creare un array. Dove viene utilizzato? Guarda il metodo put().

public V put(K key, V value) { 
    if (table == EMPTY_TABLE) { 
     inflateTable(threshold); 
    } 
    // hidden 
} 

Quando si esegue una put, la matrice viene effettivamente creata. Non ho mostrato inflateTable() ma esegue alcuni calcoli matematici e inizializza l'array.

+1

da dove proviene il codice sorgente? Ho trovato http://www.docjar.com/html/api/java/util/HashMap.java.html - ciò che dice qualcosa di diverso. Ci proverò, però :) EDIT: hai ragione, aggiungendo un put (5, "Ciao") risolve il problema. Interessante, ty –

+1

@alexberne Ho usato l'origine vista di intellij, che era 'JDK_1.7.0_51' su MacOS –

+1

Interessante ... quindi l'implementazione di OpenJDK mostrerà prestazioni diverse se hai un programma che inizializza una HashMap grande sul caricamento e mette gli elementi all'interno quando l'utente fa clic su un pulsante. - Su OpenJDK l'applicazione impiegherà molto tempo per essere caricata e sarà veloce nell'interazione dell'utente. Mentre su OracleJDK l'applicazione si caricherà velocemente e impiegherà molto tempo con il primo clic del mouse. - Il vantaggio della soluzione OracleJDK è ovviamente la possibilità di creare molte HashMap inutilizzate senza molto spazio di memoria – Falco

21

Un oggetto vuoto HashMap è molto più piccolo di una serie di 2000 riferimenti Object. Anche se si passa 2000 al parametro del costruttore 10, in realtà non si creano ancora 2000 spazi per gli oggetti.

+0

Mi sento già stupido per non saperlo. Grazie! – Eugene

Problemi correlati