2012-03-02 9 views
6

Mam aplikację, która działa w znacznym stopniu z wieloma niestandardowymi obiektami, które są tworzone wewnątrz metod i nigdy nie są potrzebne poza nimi. Cała struktura jest (moim zdaniem) bardzo dobra obiektowo zorientowana i wykorzystuje usługi, narzędzia i model DI.Jak ulepszyć aplikację, aby uniknąć problemów z przestrzenią sterty

Po uruchomieniu moich pierwszych "dużych" testów szybko natrafiłem na OutOfMemoryExceptions. Teraz nie chcę tylko zwiększać przestrzeni sterty i być z nią gotów, ponieważ mogę sobie wyobrazić, że nie rozwiąże to problemu, ale raczej opóźnię go, dopóki moja aplikacja nie rozwinie się i nie natknie się na ten sam problem.

Szukam prostych i łatwych w implementacji rozwiązań, porad i fragmentów, które pomagają aplikacjom radzić sobie z garbage collection i stertami przestrzeni, szczególnie jeśli chodzi o wiele pętli, które działają z tworzeniem obiektów.

Coś takiego jak "nie twórz obiektów w pętle, twórz je przed pętlą i nadpisuj wewnątrz" oraz sortowania.

+0

Myślę, że gdybyś mógł opublikować niektóre z twoich metod (przynajmniej struktura) byłoby o wiele łatwiej. zobacz także http://stackoverflow.com/q/627784/1163434 – gawicks

Odpowiedz

2

Zacznę od profilowania aplikacji i poszukiwania pamięciowych punktów zapalnych za pomocą jvisualvm (część JDK). To da ci i wskazanie, jak duże są twoje obiekty i jakie połączenia wywołują wysokie zużycie pamięci. Pokaże Ci także, jak długo twoje obiekty poruszają się w pamięci, co jest ogólnie dobrym punktem wyjścia, ponieważ chcesz zmniejszyć zasięg, aby był jak najkrótszy.

Następnym krokiem jest zidentyfikowanie podobieństw w obiektach poprzez udoskonalenie projektu lub wdrożenie pamięci podręcznej. Jeśli ładujesz dane ze stałego sklepu, możesz użyć miękkich odnośników, aby JVM skończyła się sterty tych obiektów będzie GCed (jeśli twoja zmiana tych obiektów będzie oczywiście potrzebna do ich usunięcia przed usunięciem twardego odniesienia). Następnie, jeśli będą potrzebne ponownie, aplikacja będzie musiała po prostu ponownie załadować je ze sklepu (DB, pliki lub cokolwiek innego).

Upewnij się, że wiesz, jak działa GC i zrozumieć Państwa obiekt nazwy:

  • /strong bezpośrednie
  • Miękkie
  • Słaby
  • Phantom

Oto kilka dobrych artykułów które wyjaśniają odniesienia i GC:

http://www.java-tips.org/java-se-tips/java.util/using-weakhashmap-for-listener-lists.html

http://pawlan.com/monica/articles/refobjs/

http://www.kdgregory.com/index.php?page=java.refobj

+1

Dzięki za linki! Bardzo pomocne programy. –

0

Anuluj odwołanie do obiektu, gdy obiekt nie jest już potrzebny? Gdy obiekt nie ma już odniesienia do niego, GC może go zebrać, ale zgaduję, że już to wiedziałeś. GC może pracować również na wykresach bez odwołań do obiektów (jeśli A ma jedyne odniesienie do B i nie ma więcej odniesienia do A, wtedy można zebrać A i B).

Bezsensowne jest wywoływanie System.gc(), ponieważ jeśli JVM potrzebuje więcej pamięci, zrobi to samodzielnie, a następnie użyje zwolnionej pamięci. Jeśli nie może uwolnić więcej pamięci, natrafisz na OOME.

Teraz domyślny rozmiar sterty nie jest zbyt duży, więc często trzeba zaakceptować większy rozmiar sterty.

Tworzenie obiektów w pętlach nie jest złym wzorcem iw wielu przypadkach jest bardzo istotne. Należy unikać powtarzania tego samego obiektu w pętli. Zazwyczaj w pętlach należy unikać konkatenacji ciągów znaków i zastępować je StringBuilderem utworzonym poza pętlą, ponieważ jest znacznie mniej wydajne pod względem wydajności, ale nie pod względem pamięci.

Nie jestem pewien, czy naprawdę odpowiem na twoje pytanie.

4

Najważniejsza rada, że ​​mogę dać ci jest taka sama jak w przypadku każdego problemu z wydajnością:

Profil, poprawić, powtórzyć

pomocą profilera (np VisualVM), aby dowiedzieć się, gdzie zużywa największą ilość pamięci. Ulepsz swój kod, najpierw usuń wszelkie wycieki pamięci, a następnie zmniejsz ogólnie zużycie pamięci. Powtarzaj ten proces, aż będziesz zadowolony z jakości i wydajności swojego kodu.

EDIT:

Kilka sztuczek handlu:

  • Udostępnianie obiektów zamiast powielać, jeśli to możliwe.

  • Uwaga na klasy kolekcji Java (tj. Różne implementacje Collection<T> i Map<K,V>). W zależności od tego, co przechowujesz i od tego, jaka jest kolekcja w użyciu, możesz bez trudu oczekiwać, że będzie to increase your memory consumption by an order of magnitude.

  • Podczas gdy Java nie ma (zwykle) przecieków pamięci w tym samym sensie co napotkane w C, kod Java często ma problem z obiektami, które są utrzymywane przy życiu po ich dacie wygaśnięcia.

    Aby tego uniknąć, należy maksymalnie ograniczyć zakres referencji lub ustawić je na null po zakończeniu pracy z tym obiektem. Uwaga: nie rób tego zbyt często przy pomocy ustawienia null, zwłaszcza w prostych metodach, które wkrótce powrócą.

    Co najważniejsze: upewnij się, że usuniesz obiekt z kolekcji, w które został on wprowadzony, gdy skończysz. Nie jest to dobry przepis na OutOfMemoryError - i najczęstszą przyczynę tego, co ludzie nazywają wyciekiem pamięci w świecie Java.

+0

+1: Rozważę również komercyjny profiler, jeśli VisualVM nie wystarczy. Używam YourKit. –

5

Niektóre punkty:

  • Nie ma nic fundamentalnie złego zwiększając przestrzeń sterty. Różne aplikacje mają różne wymagania.
  • Użyj profilera, aby zobaczyć, co naprawdę się dzieje. Na przykład tutaj można znaleźć sterty analizatora: MAT
  • Kiedy okazuje się, że przypadki pewnej klasy są odpowiedzialne za 80% zużycia sterty:
    • spróbować znaleźć powszechnie udostępniony zestaw zmiennych o tych samych wartościach. Są kandydatami na jeden obiekt, który może być współdzielony przez wiele obiektów.
    • Sprawdź, czy przechowujesz jakieś odniesienie do stosunkowo dużego wykresu obiektu do zmiennej, która żyje znacznie dłużej niż twoje pętle (zmienne lokalne zużywają stos).
    • Pozwolić, aby odniesienia wyszły poza zakres tak szybko, jak to możliwe.
    • Jeśli używasz klas wewnętrznych, sprawdź te, które nie są statyczne, ponieważ niestatyczna klasa wewnętrzna odwołuje się do obiektu zawierającego.
+0

Bardzo podoba mi się twoja 4 podpulchów (+1) – DaveFar

+2

+1 dla odniesienia do klas wewnętrznych. Mają sporo pułapek, z którymi większość ludzi nie zdaje sobie sprawy ... – thkala

0

Po pierwsze, chciałbym ponownie sprawdzić mój projekt, koncentrując się na potrzebnego górnej złożoności (Landau/Big O notation).

Po drugie, chciałbym przeczytać Josh Bloch's Effective Java, Item 6 (Eliminacja przestarzałych odniesień obiektu), aby uzyskać pewne wskazówki na temat

  • częste powody do „wycieku pamięci”
  • raczej stosując najmniejszą możliwą zakres następnie znoszący nie potrzebne obiekty
  • Baseny do buforowania i przechowywania.

Po trzecie, jeśli jeszcze wyjątki OOM, będę śledzić Mikko's advises.

Powiązane problemy