2010-06-30 15 views
7

Pisałem małą aplikację Java (moja pierwsza!), Która w tej chwili zajmuje tylko kilka rzeczy. Obecnie uruchamia klasę Main, która uruchamia klasę gui (klasa, którą napisałem, która rozszerza JFrame, która zawiera tylko JTextArea), klasę, która ładuje lokalny plik przez BufferedInputStream, który ma około 40kb, oraz klasę, która ładuje wpis z Plik właściwości Java.Użycie pamięci aplikacji Java

Wszystko działa cudownie, jednak obserwowałem menedżera zadań systemu Windows i zauważyłem coś, co wydało mi się dziwne. Kiedy uruchamiam aplikację, użycie pamięci RAM przeskakuje do około 40 MB podczas ładowania lokalnego pliku i pobiera z niego kilka wartości do wyświetlenia w JTextArea, co wydaje mi się normalne z powodu JVM, klas bazowych Java itd. W tym przypadku jednakże, gdy aplikacja zakończy ładowanie pliku, jest ona nieaktywna, ponieważ obecnie nie robię nic innego. Gdy jest ono nieaktywne, tak długo, jak okno jest aktywne, użycie pamięci aplikacji zaczyna się zwiększać o 10-20kb na sekundę. To wydaje mi się dziwne. Jeśli kliknę na inny program, aby uczynić z niego nieaktywne okno, pamięć wciąż rośnie, ale z dużo wolniejszym tempem (około 10kb co 3-5 sekund).

Nie testowałem, żeby zobaczyć, jak daleko się to skończy, ale to wydaje mi się bardzo dziwnym zachowaniem. Czy to normalne zachowanie Java? Sądzę, że jest możliwe, że mój kod może być przeciekającą pamięcią, ale nie jestem pewien jak. Upewniłem się, aby zamknąć BufferedInputStream używam, i nie widzę, co jeszcze spowoduje to.

Przykro mi, jeśli moje wyjaśnienie nie ma sensu, ale byłbym wdzięczny za wszelkie wgląd i/lub wskazówki, które ktoś może mieć.

UPDATE:

Na sugestię, że w zasadzie pozbawiony mojej aplikacji w dół do głównej klasy, która po prostu wywołuje klasę GUI. Klasa gui rozszerza tylko ramkę JFrame i ustawia rozmiar okna, zamknięcie operacji i widoczne właściwości. Dzięki tym zmianom pamięć wciąż rośnie w tempie 10-20 kb, ale w wolniejszym tempie. To, w połączeniu z innymi poradami, które otrzymałem, prowadzi mnie do przekonania, że ​​to tylko Java. Będę z nim dalej grał i dam znać, jeśli dowiem się czegoś ciekawego.

+0

Gratulacje za pierwszą aplikację !!! Może mógłbyś napisać jakiś kod? Bez kodu po prostu zgadujemy. Po prostu monitoruj go, aby zobaczyć, czy naprawdę rośnie, czy po prostu przestaje w pewnym momencie. Opublikuj swoje wyniki. –

+1

@Romain, dzięki! Myślałem o opublikowaniu mojego kodu, ale szczerze mówiąc, bardziej interesowało mnie, czy jest to normalne zachowanie Java (nie sądziłem, ale wszystko jest możliwe!). Zbadam więcej, a następnie opublikuję kod, jeśli nie będę w stanie zrozumieć, dlaczego za kilka dni. Dzięki! –

+1

#masternosaj To normalne, że pamięć zmienia niektóre z nich jako wewnętrznie odświeżane na ekranie, a odśmiecanie jest wykonywane. Nie jest normalne, aby pamięć wciąż rosła. Jeśli jesteś początkującym językiem Java, widziałem ludzi pytających o recenzje kodu sekcji kodu na tej stronie. –

Odpowiedz

9

Spróbuj monitorowanie użycia sterty z JConsole zamiast menedżera zadań Windows:

  • Uruchom aplikację z opcją -Dcom.sun.management.jmxremote np

java -Dcom.sun.management.jmxremote -jar myapp.jar

  • Wprowadzenie jconsole z linii poleceń i łączyć się z lokalnym PID procesu java została uruchomiona w ostatnim etapie.
  • Kliknij na pamięci i oglądać pamięci sterty (Ekran domyślny)

Jeśli obserwować przez jakiś czas, prawdopodobnie będziesz dostać „zębów piły” wzór jako pamięć wspina się w czasie, ale ma ostry drop-offs, gdy uruchamia się garbage collector. Możesz spróbować "zasugerować" wyrzucenie śmieci, klikając przycisk z tak oznaczoną etykietą.

Kiedy to zrobisz, czy zużycie pamięci spadnie do tego samego minimalnego poziomu, czy też całkowite minimalne zwiększenie w ciągu kilku minut? Jeśli minimalne zużycie wzrasta, oznacza to wyciek pamięci.Jeśli zawsze powróci do tego samego minimalnego poziomu, wszystko jest w porządku.

+1

to była bardzo wnikliwa odpowiedź. Spróbuję! –

+1

Dałem próbkę JConsole i jest to całkiem sprytne narzędzie. Jak zauważyłem, wykorzystanie pamięci sterty stale rosło. Po wywołaniu GC (za pomocą przycisku, o którym wspomniałeś), zużycie pamięci zostało dnem. Próbowałem tego kilka razy i zawsze spadało do tego samego minimalnego poziomu. Dziękuję bardzo! –

+2

Należy pamiętać, że JDK 6 ma jeszcze bardziej użyteczną funkcję: JVisualVM. Uruchom go, wpisując polecenie 'jvisualvm' w wierszu polecenia. – Jesper

2

Gratulacje za pierwszą aplikację! Teraz kilka rzeczy do przemyślenia. Po pierwsze, menedżer zadań Windows nie jest świetnym zasobem, który pozwala zrozumieć, jak szybko rośnie twój vm. Zamiast tego należy monitorować statystyki zbierania śmieci w konsoli (użyj parametru linii komend -verbose:gc). Po drugie, jeśli obawiasz się potencjalnych wycieków i wzrostu vm, istnieje grupa świetnych profilerów, które są łatwe w użyciu i mogą pomóc w diagnozowaniu problemów z pamięcią. sprawdź te twoposts dla niektórych opcji profilera.

+1

@afk, Dzięki! Słyszałem, że Menedżer zadań systemu Windows nie był najlepszym narzędziem do monitorowania aplikacji Java, ale nie wiedziałem, jak wiarygodne są te informacje. Dobrze sprawdzam, o czym wspomniałeś. –

2

Gratulacje dla Twojej pierwszej aplikacji Java!

Aplikacje Java działają na maszynie wirtualnej. Maszyna wirtualna ma przypisaną stałą ilość pamięci przez system operacyjny, zwykle 512 MB. Dopóki aplikacja zużywa mniej niż 512 MB, garbage collector nie uruchomi się i rozpocznie wyszukiwanie "martwych" bloków pamięci. Limit pamięci JVM można modyfikować w większości systemów operacyjnych. Spróbuj na przykład zmienić limit pamięci na 32 MB.

+1

dzięki! Będę o tym pamiętać. Spróbuję zobaczyć, jak daleko się to naprawdę wznosi. Dzięki za sugestie. –

+0

zasadniczo jest poprawna, ale żadna JVM, z którą się zetknąłem, nie przydzieli początkowego sterty dużego (512 MB) ... chyba że coś konkretnie powie mu za pomocą opcji uruchamiania maszyny JVM. –

1

Czy to normalne zachowanie Java?

Nie.

Myślę, że to możliwe, że mój kod może być nieszczelny pamięć

To zdecydowanie przyczyną. Proszę napisać swój kod źródłowy, w przeciwnym razie dalsza diagnoza nie jest możliwa.

Zauważyłem, że używasz Swing, upewnij się, że uruchamiasz swoją JFrame w event dispatch thread, używając metody invokeLater(Runnable).

Jeśli używasz dowolnego rodzaju kolekcji, upewnij się, że raz je wykonałeś.

Ponieważ robisz plik IO, upewnij się, że zamknąłeś wszystkie klasy zaangażowane w operacje IO po ich zakończeniu.

Jeśli używasz dowolnego detektora zdarzeń, pamiętaj, aby jawnie usunąć detektory zdarzeń, gdy nie są już potrzebne.


Jedno można spróbować eksperymentuje. Weź swoją aplikację i usuń plik IO, zobacz, co się stanie. Czy użycie pamięci nadal rośnie tak jak wcześniej? Teraz zresetuj swoją aplikację do normalnego poziomu i usuń obszar tekstowy - czy pamięć nadal jest tak jak poprzednio? Itd., Itp. To pomoże ci ustalić, co jest źródłem, i możesz skupić swoje wysiłki tam. Najprawdopodobniej odkryjesz, co robisz, robiąc to.

Innym przydatnym narzędziem diagnozy jest użycie System.gc() w poszczególnych punktach czasowych, zwykle po bloków ciężkich podnoszenia kodu. Dzięki temu JVM będzie wykonywać odśmiecanie w tym momencie wykonywania, a nie w innym czasie określonym przez zużycie pamięci. Pomoże to uwzględnić wszelkie okresowe wahania zużycia pamięci w aplikacji.

W przypadku niepowodzenia, zawsze można użyć profilera pamięci. Jeśli korzystasz z IDE Netbeans, jest wbudowany w niego. W przypadku Eclipse istnieje kilka wtyczek, które mogą wykonywać profilowanie.

+1

Jak to jest pomocne? –

+0

Tak, to jest Java. Sobie z tym poradzić. – matiasf

+1

@bguiz Nie jestem pewien, czy rozumiem co masz na myśli przez wątek wysyłki zdarzenia. Jestem bardzo nowy w Javie i nie widziałem, o czym wspominałem. –

1

To normalne. niektóre tła mogą pozostawić martwe obiekty, które JVM nie spieszy się do sprzątania. w końcu będą zbierane śmieci, kiedy zbliża się max mem.

zostaw program na noc, a Twoja maszyna nie wysadzi się.

+1

dziękuję, będę o tym pamiętać. –