2013-08-22 4 views
27

Jakie są zalety i wady opróżniania kolekcji (w moim przypadku jest to ArrayList), a nie tworzenia nowej (i umożliwiania odśmiecania starego).Opróżnij tablicę ArrayList lub po prostu utwórz nową i pozwól starym zebrać śmieci?

W szczególności mam ArrayList<Rectangle> o nazwie list. Kiedy pojawia się pewien warunek, muszę opróżnić list i uzupełnić go o inne treści. Czy powinienem zadzwonić pod numer list.clear() lub po prostu złożyć nowy ArrayList<Rectangle> i pozwolić staremu na zbieranie śmieci? Jakie są plusy i minusy każdego podejścia?

+0

Nie ma pewności, kiedy obiekt będzie faktycznie zbiorem śmieci, więc myślę, że najlepiej byłoby opróżnić i użyć go ponownie. Nie jestem jednak mistrzem w używaniu pamięci, więc z chęcią zobaczę, jakie inne odpowiedzi uzyska ta odpowiedź. – Vulcan

+0

'list.clear()' to zależy od kontekstu, czy masz jakieś inne odniesienia odnoszące się do tej samej listy? – nachokk

+0

Brak innych referencji – Cricketer

Odpowiedz

27

Przechowujesz kontener i dzwonisz pod numer clear, gdy chcesz zmniejszyć obciążenie GC: clear() usuwa wszystkie odwołania wewnątrz tablicy, ale nie powoduje, że tablica może zostać odzyskana przez moduł czyszczenia pamięci. Może to przyspieszyć przyszłe wstawki, ponieważ tablica wewnątrz ArrayList nie musi się rozwijać. To podejście jest szczególnie korzystne, gdy dane, które planujesz dodać do kontenera, mają mniej więcej taki sam rozmiar, jak te, które usuwasz.

Ponadto może być konieczne użycie clear, gdy inne obiekty zawierają odniesienie do tablicy, którą chcesz wyczyścić.

Uwalnianie kontenera i tworzenie nowego ma sens, gdy rozmiar nowych danych może być inny niż wcześniej. Oczywiście można osiągnąć podobny efekt, dzwoniąc pod numer clear() w połączeniu z trimToSize().

0

To naprawdę nie ma znaczenia ...

List.clear() realizacja ustawia odniesienia tablicy wewnętrznej do null. Skuteczne ustawienie obiektów do zbierania śmieci, jeśli nie ma więcej odniesień.

Jeśli Twoim jedynym zmartwieniem jest pamięć, nie ma rzeczywistej wymiernej różnicy w obu podejściach. Nawet jeśli chodzi o działanie, różnica będzie dotyczyć alokacji tablic (w operacjach zmiany rozmiaru) i innych takich operacji.

Ale czyszczenie go może być nieznacznie lepsze, chociaż jeśli utworzenie nowej listy jest bardziej czytelne, skorzystam z tego.

+0

* "Jeśli twoim jedynym zmartwieniem jest pamięć, nie ma żadnej realnej mierzalnej różnicy w obu podejściach." * - W rzeczywistości nie jest to ściśle prawdziwe. Będzie pewna wymierna różnica ... jeśli zmierzysz ilość wolnego miejsca w stercie. (I to jest ignorowanie innych rzeczy, które można/należy zmierzyć, np. Wykorzystanie procesora i obciążenie stronicowania.) –

38

Zaletą recyklingu ArrayList (na przykład poprzez wywołanie clear) jest to, że można uniknąć napowietrznej przydzielenie nowego, a koszt rośnie to ... jeśli nie zapewniają dobrą initialCapacity podpowiedź.

Wady zawracanie do obiegu ArrayList obejmują:

  • Sposób clear() musi nadać null do każdej (stosowane) szczeliny w ArrayList s nośnej tablicy.

  • Numer clear() nie zmienia rozmiaru tablicy, aby zwolnić pamięć. Więc jeśli wielokrotnie wypełniasz i czyścisz listę, to skończy się ona (na stałe) przy użyciu wystarczającej ilości pamięci, aby reprezentować największą listę, jaką napotka. Innymi słowy, zwiększyłeś ślad pamięci. Możesz to zwalczyć, wywołując trimToSize() ... który tworzy obiekt śmieci, etcetera.

  • Występują problemy lokalne i międzypokoleniowe, które mogą wpływać na wydajność. Gdy wielokrotnie odtwarzasz obiekt ArrayList, obiekt i jego tablica podkładowa prawdopodobnie zostaną utrwalone.Oznacza to, że:

    • obiektów list i obiekty reprezentujące elementy listy mogą być w różnych obszarach stercie, potencjalnie zwiększając tęskni TLB i ruchu stron, zwłaszcza w czasie GC.

    • Przypisanie referencji (młodej generacji) do tablicy (na liście) (na liście) często wiąże się z kosztami napitku zapisu ... w zależności od implementacji GC.


Nie jest możliwe dokładne modelowanie wydajności kompromisów dla aplikacji rzeczywistych. Jest po prostu zbyt wiele zmiennych. Jednak "otrzymana mądrość" jest taka, że ​​recykling NIE jest zwykle dobrym pomysłem, jeśli masz dużo pamięci i przyzwoitego śmieciarza.

Warto również zauważyć, że nowoczesna maszyna JVM może bardzo wydajnie rozmieszczać obiekty. Wystarczy jedynie zaktualizować "wolny" wskaźnik stosu i napisać 2 lub 3 słowa nagłówka obiektu. Wyzerowanie pamięci jest wykonywane przez GC ... a poza tym praca w ten sposób jest z grubsza równoważna z pracą, którą clear() robi, aby usunąć odnośniki na liście, która jest poddawana recyklingowi.

1 - Kolektor do kopiowania jest bardziej wydajny, jeśli odsetek obiektów śmieciowych w obiektach innych niż śmieci jest wysoki. Jeśli przeanalizuje się sposób działania tego rodzaju kolektora, koszty są prawie wszystkie poniesione podczas wyszukiwania i kopiowania dostępnych obiektów. Jedyne, co należy zrobić, aby usunąć śmieci, to zablokować-zero-pisać ewakuowaną przestrzeń "z", gotową do przydzielenia nowych obiektów.


Moja rada byłaby nie do recyklingu ArrayList obiektów, chyba że masz udowodnić potrzebę minimalizacji (śmieci) szybkość tworzenia obiektów; na przykład ponieważ jest to jedyna opcja do ograniczenia (szkodliwych) wstrzymań GC.

Wszystkie rzeczy są równe, na nowoczesnym Hotspot JVM mój zrozumienia jest to, że dostaniesz najlepszą wydajność, wykonując następujące czynności:

  • Przydzielanie nowych obiektów ArrayList zamiast recyklingu.
  • Używaj dokładnych initialSize wskazówek, kiedy przydzielasz obiekty listy. Lepiej jest nieco przeszacować niż nieznacznie zaniżać.
+1

punkt miejscowości jest najbardziej interesujący, ponieważ dla mnie było to mniej oczywiste. – marcorossi

0

Jak już pisano ciekawe punkty, można myśleć o tym nawet o jeden poziom głębiej.

Ja nie zdało sobie sprawę, niż czytałem artykuł o disruptoraa wzór, patrz How does LMAX's disruptor pattern work?

Jest to możliwe nie tylko do ponowne bazowego kolekcja, można ponowne również podmiotów w terminie kolekcja.

E.g. przypuśćmy, że przypadek producenta i konsumenta. Producent może wielokrotnie wprowadzać dane do tej samej (cyklicznej) tablicy, a nawet używać tych samych elementów.Po prostu usuń właściwości, stan wewnętrzny i wypełnij go.

To o jeden poziom lepsze rozwiązanie w widoku GC. Ale to oczywiste, że nie jest to przydatne w przypadku każdego problemu.

Powiązane problemy