2015-07-14 14 views
44

Próbowałem zbudować własną Mapę, aby zwiększyć wydajność w specyficznym środowisku i zdałem sobie sprawę z czegoś bardzo interesującego: Tworzenie new Hashmap<Integer,String>(2000) jest szybsze niż new Object[2000] - bez względu na kolejność wykonywania tych poleceń. To jest dla mnie dość mylące, szczególnie. ponieważ konstruktor Hashmap zawiera table = new Entry[capacity], zgodnie z this. Czy coś jest nie tak z moim testbenchem?Dlaczego tworzenie HashMap jest szybsze niż tworzenie obiektu []?

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 
} 

Chciałbym zobaczyć wyniki testów na innym komputerze. Nie mam pojęcia, dlaczego tworzenie HashMap jest 10 razy szybsze niż tworzenie Object[].

+0

To zależy od implementacji JDK. Którego JDK i wersji używasz do przeprowadzenia tego testu? – BladeCoder

+0

@BladeCoder Używam wersji 1.7.0_79 (IceTea 2.5.5) (7u79-2.5.5-0ubuntu0.14.04.2) zgodnej z java.version. –

+4

Rzeczywiście, w zamkniętej wersji OpenJDK 1.7, żadna tablica nie jest inicjowana w konstruktorze HashMap (odbywa się to przy pierwszym wstawianiu), co tłumaczy luki prędkości: http://grepcode.com/file_/repository.grepcode.com/java/ root/jdk/openjdk/7u40-b43/java/util/HashMap.java /? v = source – BladeCoder

Odpowiedz

51

Jeśli spojrzeć na realizację HashMap, konstruktor wygląda następująco:

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

I init() wygląda następująco:

/** 
* 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() { 
} 

Więc initialCapacity faktycznie nie przyzwyczaić się do utworzenia tablicy. Gdzie to się stosuje? Spójrz na metodę put().

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

Podczas robienia, tablica jest faktycznie tworzona. Nie pokazałem inflateTable(), ale wykonuje ona trochę matematyki i inicjuje tablicę.

+1

Skąd pochodzi kod źródłowy? Znalazłem http://www.docjar.com/html/api/java/util/HashMap.java.html - co mówi coś innego. Spróbuję, ale :) EDYCJA: masz rację, dodanie put (5, "Hello") rozwiązuje problem. Interesujące, ty –

+1

@alexberne Użyłem źródła widoku intellij, które było 'JDK_1.7.0_51' na MacOS –

+1

Ciekawe ... więc implementacja OpenJDK będzie pokazywała inną wydajność, jeśli masz program, który inicjuje duży HashMap na ładowanie i umieszcza elementy wewnątrz, gdy użytkownik kliknie przycisk. - W OpenJDK aplikacja ładuje się długo i działa szybko podczas interakcji użytkownika. W OracleJDK aplikacja ładuje się szybko i zajmuje pierwsze kliknięcie. - Zaletą rozwiązania OracleJDK jest oczywiście możliwość tworzenia wielu nieużywanych map HashMaps bez dużego nakładu pamięci. – Falco

21

Pusty obiekt HashMap jest znacznie mniejszy niż tablica z 2000 Object odniesień. Nawet jeśli zdasz 2000 do parametru initialCapacity konstruktora HashMap, to nie tworzy on jeszcze 2000 spacji dla obiektów.

+0

Już czuję się głupio, że o tym nie wiem. Dzięki! – Eugene

Powiązane problemy