2010-05-11 9 views
36

Rozważmy follwing kod HashMap.clear():Czy pamięć Java HashMap.clear() i remove() jest skuteczna?

/** 
* Removes all of the mappings from this map. 
* The map will be empty after this call returns. 
*/ 
public void clear() { 
    modCount++; 
    Entry[] tab = table; 
    for (int i = 0; i < tab.length; i++) 
     tab[i] = null; 
    size = 0; 
} 

Wydaje się, że tablica wewnętrzna (table) od Entry przedmiotów nigdy się kurczyły. Tak więc, kiedy dodaję 10000 elementów do mapy, a po tym wywołaniu map.clear(), zachowa ona 10000 zer w wewnętrznej tablicy. Moje pytanie brzmi: w jaki sposób JVM radzi sobie z tą tablicą nici, a co za tym idzie, czy pamięć jest efektywna?

+5

10 000 wartości zerowych zajmuje całe 40 KB (być może 80 na 64-bitowej maszynie JVM). –

+8

@Michael, być może, ale to nie ma znaczenia: numer można rozszerzyć na dowolną skalę. PO zadaje zasadę. Może mapa jest ogromna, może dostępna pamięć jest mała. Nie wiemy. – corsiKa

+2

10000 elementów na mapie! = 10000 wpisów w wewnętrznej tabeli. proszę się dowiedzieć, jak działa HashMap imp ... – james

Odpowiedz

57

Chodzi o to, że clear() jest wywoływane tylko wtedy, gdy chcesz ponownie użyć HashMap. Ponowne użycie obiektu powinno się odbywać tylko z tego samego powodu, z jakiego było wcześniej używane, więc istnieje prawdopodobieństwo, że będziesz miał mniej więcej taką samą liczbę wpisów. Aby uniknąć niepotrzebnego obkurczania i zmieniania rozmiaru Map, pojemność jest utrzymywana na tym samym poziomie, gdy wywoływana jest clear().

Jeśli wszystko, co chcesz zrobić, to usunąć dane w Map, wtedy nie trzeba (i faktycznie nie powinna) nazywamy clear() na nim, ale po prostu oczywiste, wszystkie odniesienia do samego Map, w tym przypadku będzie to śmieci zebrane w końcu.

+0

Dodam też, że to zachowanie nie jest częścią udokumentowanej umowy, więc nawet jeśli natknąłeś się na implementację, która * zmieniła * wewnętrzną tablicę - co wydaje się nieprawdopodobne - to ty prawdopodobnie nie powinien polegać na tym, chyba że wyraźnie stanowi część umowy. –

+1

To dobrze, ale co jeśli HashMap jest używany w jakimś singletone i zawsze zawiera pewne dane, więc nie może być zastąpiony przez nową instancję? W niektórych przypadkach może uzyskać dużą porcję danych, która będzie tam przez jakiś czas, a następnie zostanie usunięta. Ale wartości null w tablicy pozostaną. To nie wygląda dobrze. –

+5

@Shaman: wszystko, co właśnie podałeś, to kolejny powód, dla którego nie należy używać wzorca singlton ;-) –

4

Masz rację, ale biorąc pod uwagę, że zwiększenie macierzy jest znacznie droższą operacją, nie jest nierozsądne, aby HashMap pomyślał "kiedy użytkownik zwiększy tablicę, prawdopodobnie będzie potrzebował tablicy tej wielkości ponownie później "i po prostu opuść tablicę zamiast jej zmniejszać i ryzykować, że będziesz musiał później kosztownie ją rozbudować. Przypuszczam, że to heurystyka - można by też bronić się na odwrót.

4

Inną rzeczą, którą należy wziąć pod uwagę, jest to, że każdy element w table jest po prostu referencją. Ustawienie tych pozycji na wartość null spowoduje usunięcie odniesień z elementów w twoim Map, które będą wtedy wolne dla usuwania śmieci. Tak więc nie jest tak, że nie uwalniasz żadnej pamięci.

Jeśli jednak chcesz zwolnić nawet pamięć używaną przez samą Map, należy ją zwolnić zgodnie z sugestią Joachima Sauera.

9

Looking at the source code, to wygląda jak HashMap nigdy się nie kurczy. Metoda resize jest wywoływana w celu podwojenia rozmiaru w razie potrzeby, ale nie ma niczego ala ArrayList.trimToSize().

Jeśli używasz HashMap w taki sposób, że rośnie i kurczy się znacznie częściej, może chcesz po prostu stworzyć nową HashMap zamiast dzwonić clear().

Powiązane problemy