Wiem, że w Javie zbieranie śmieci jest zautomatyzowane. Ale zrozumiałem, że jeśli wywołasz System.gc()
w swoim kodzie, że JVM może, ale nie musi, zdecydować o przeprowadzeniu czyszczenia pamięci. Jak to dokładnie działa? Na jakiej podstawie / parametrach dokładnie maszyna JVM decyduje się wykonać (lub nie) wykonać GC, gdy widzi System.gc()
?
Czy są jakieś przykłady, w których przypadku warto umieścić to w swoim kodzie?
java
garbage-collection
Michael
źródło
źródło
Odpowiedzi:
W praktyce zazwyczaj decyduje się na usuwanie elementów bezużytecznych. Odpowiedź różni się w zależności od wielu czynników, takich jak JVM, na którym działa, w jakim trybie się znajduje i jakiego algorytmu czyszczenia pamięci używa.
Nie polegałbym na tym w twoim kodzie. Jeśli JVM ma wyrzucić błąd OutOfMemoryError, wywołanie System.gc () go nie zatrzyma, ponieważ moduł odśmiecania pamięci będzie próbował uwolnić jak najwięcej, zanim osiągnie skrajność. Jedyny raz, kiedy widziałem, jak jest używany w praktyce, to w IDE, gdzie jest dołączony do przycisku, który użytkownik może kliknąć, ale nawet tam nie jest to zbyt przydatne.
źródło
System.gc()
na ekranie ładowania gry wideo. W tym momencie nie obchodzi mnie, czy wezwanie wyczyści wszystko, co możliwe, lub w ogóle nic nie zrobi. Chciałbym jednak wolę , że „wysiłek poświęcać kierunku recykling nieużywanych obiektów” podczas ekranie ładowania, a nie w czasie rozgrywki.Jedynym przykładem, w którym mogę wymyślić sens wywoływanie System.gc (), jest profilowanie aplikacji w celu wyszukiwania możliwych wycieków pamięci. Uważam, że osoby odpowiedzialne za profilowanie wywołują tę metodę tuż przed zrobieniem migawki pamięci.
źródło
Specyfikacja języka Java nie gwarantuje, że maszyna JVM uruchomi GC po wywołaniu
System.gc()
. To jest powód tego „może, ale nie musi, zdecydować się na przeprowadzenie GC w tym momencie”.Teraz, jeśli spojrzysz na kod źródłowy OpenJDK , który jest kręgosłupem Oracle JVM, zobaczysz, że wywołanie wywołania
System.gc()
rozpoczyna cykl GC. Jeśli używasz innej maszyny JVM, takiej jak J9, musisz sprawdzić jej dokumentację, aby znaleźć odpowiedź. Na przykład maszyna JVM firmy Azul ma moduł wyrzucania elementów bezużytecznych, który działa w sposób ciągły, więc wywołanieSystem.gc()
nic nie daInne odpowiedzi wspominają o uruchomieniu GC w JConsole lub VisualVM. Zasadniczo te narzędzia wykonują zdalne wywołanie
System.gc()
.Zwykle nie chcesz rozpoczynać cyklu wyrzucania elementów bezużytecznych z kodu, ponieważ wprowadza on w błąd semantykę aplikacji. Twoja aplikacja robi pewne rzeczy biznesowe, JVM zajmuje się zarządzaniem pamięcią. Powinieneś oddzielić te obawy (nie zmuszaj aplikacji do zarządzania pamięcią, skup się na biznesie).
Jednak jest kilka przypadków, w których wezwanie
System.gc()
może być zrozumiałe. Rozważmy na przykład mikroznak. Nikt nie chce, aby cykl GC odbywał się w środku mikroznaku. Możesz więc wyzwolić cykl GC między każdym pomiarem, aby upewnić się, że każdy pomiar zaczyna się od pustej sterty.źródło
Nie masz kontroli nad GC w java - decyduje maszyna wirtualna. Nigdy nie trafiłem na przypadek, w którym
System.gc()
jest to potrzebne . PonieważSystem.gc()
wywołanie po prostu SUGERUJE, że maszyna wirtualna usuwa elementy bezużyteczne, a także wykonuje PEŁNE wyrzucanie elementów bezużytecznych (stare i nowe generacje w stosie wielopokoleniowym), może to spowodować zużycie WIĘCEJ cykli procesora niż jest to konieczne.W niektórych przypadkach warto zasugerować maszynie wirtualnej, aby zrobiła całą kolekcję TERAZ, ponieważ być może wiesz, że aplikacja będzie bezczynna przez kilka następnych minut, zanim nastąpi duże obciążenie. Na przykład, zaraz po zainicjowaniu wielu tymczasowych obiektów podczas uruchamiania aplikacji (tj. Właśnie zapisałem w pamięci podręcznej TONĘ informacji i wiem, że przez minutę lub więcej nie będę miał dużo aktywności). Pomyśl o IDE, takim jak uruchamianie zaćmienia - inicjalizuje ono wiele, więc być może natychmiast po inicjalizacji sensowne jest wykonanie pełnego gc w tym momencie.
źródło
Musisz bardzo uważać, kiedy dzwonisz
System.gc()
. Wywołanie go może spowodować niepotrzebne problemy z wydajnością w aplikacji i nie gwarantuje rzeczywistego wykonania kolekcji. W rzeczywistości można wyłączyć jawneSystem.gc()
za pomocą argumentu java-XX:+DisableExplicitGC
.Gorąco polecam przeczytanie dokumentów dostępnych w Java HotSpot Garbage Collection, aby uzyskać bardziej szczegółowe informacje na temat czyszczenia pamięci.
źródło
System.gc()
jest implementowana przez maszynę wirtualną, a jej działanie zależy od implementacji. Na przykład osoba wdrażająca może po prostu wrócić i nic nie robić.Jeśli chodzi o wydanie ręcznej zbiórki, jedynym momentem, w którym możesz chcieć to zrobić, jest porzucenie dużej kolekcji zawierającej mnóstwo mniejszych kolekcji -
Map<String,<LinkedList>>
na przykład - i chcesz spróbować wtedy osiągnąć perfekcyjny hit i tam, ale w większości nie powinieneś się tym martwić. GC wie lepiej niż ty - niestety - przez większość czasu.źródło
Jeśli używasz bezpośrednich buforów pamięci, JVM nie uruchomi GC za Ciebie, nawet jeśli masz mało pamięci bezpośredniej.
Jeśli zadzwonisz
ByteBuffer.allocateDirect()
i otrzymasz OutOfMemoryError, możesz stwierdzić, że to wywołanie jest w porządku po ręcznym uruchomieniu GC.źródło
Cleaners
którego używa pamięć bezpośrednia. tj. nie jest zwalniany przez wątek finalizujący, ponieważ może to być zbyt wolne. Mimo to możliwe jest uzyskanie OOME, jeśli szczególnie szybko tworzysz bezpośrednie regiony pamięci. Rozwiązaniem jest, aby tego nie robić i ponownie wykorzystywać swoje bezpośrednie regiony pamięci tam, gdzie jest to możliwe.Większość maszyn JVM uruchomi GC (w zależności od przełącznika -XX: DiableExplicitGC i -XX: + ExplicitGCInvokesConcurrent). Ale specyfikacja jest po prostu gorzej zdefiniowana, aby później umożliwić lepsze implementacje.
Specyfikacja wymaga wyjaśnienia: Bug # 6668279: (specyfikacja) System.gc () powinien wskazywać, że nie zalecamy używania i nie gwarantujemy zachowania
Wewnętrznie metoda gc jest używana przez RMI i NIO i wymagają one synchronicznego wykonywania, co: jest obecnie omawiane:
Błąd nr 5025281: Zezwalaj System.gc () na wyzwalanie współbieżnych (bez zatrzymywania świata) pełnych kolekcji
źródło
Garbage Collection
jest dobryJava
, jeśli wykonujemy oprogramowanie zakodowane w Javie na komputerze stacjonarnym / laptopie / serwerze. Można zadzwonićSystem.gc()
lubRuntime.getRuntime().gc()
wJava
.Pamiętaj tylko, że żadne z tych połączeń nie gwarantuje nic. To tylko sugestia dla jvm, aby uruchomić Garbage Collectora. To zależy od JVM, czy obsługuje GC, czy nie. Krótka odpowiedź: nie wiemy, kiedy działa. Dłuższa odpowiedź: JVM uruchomiłoby gc, gdyby miał na to czas.
Myślę, że to samo dotyczy Androida. Może to jednak spowolnić system.
źródło
Zwykle maszyna wirtualna automatycznie wyrzucałaby elementy bezużyteczne przed wyrzuceniem wyjątku OutOfMemoryException, więc dodanie jawnego wywołania nie powinno pomóc, z wyjątkiem tego, że być może przenosi działanie wydajności na wcześniejszy moment.
Myślę jednak, że spotkałem się z przypadkiem, w którym może to mieć znaczenie. Nie jestem jednak pewien, ponieważ jeszcze nie przetestowałem, czy to ma jakikolwiek efekt:
Kiedy mapujesz plik w pamięci, uważam, że wywołanie map () zgłasza IOException, gdy wystarczająco duży blok pamięci jest niedostępny. Myślę, że czyszczenie pamięci tuż przed plikiem map () mogłoby temu zapobiec. Co myślisz?
źródło
nigdy nie możemy wymusić czyszczenia pamięci. System.gc sugeruje tylko vm do czyszczenia pamięci, jednak tak naprawdę, o której godzinie działa mechanizm, nikt nie wie, tak jest w specyfikacji JSR.
źródło
Jest wiele do powiedzenia w poświęceniu czasu na przetestowanie różnych ustawień czyszczenia pamięci, ale jak wspomniano powyżej, zwykle nie jest to przydatne.
Obecnie pracuję nad projektem obejmującym środowisko o ograniczonej pamięci i stosunkowo duże ilości danych - jest kilka dużych fragmentów danych, które przesuwają moje środowisko do granic możliwości i mimo że udało mi się zmniejszyć zużycie pamięci, więc że teoretycznie powinno działać dobrze, nadal otrzymywałbym błędy dotyczące miejsca na stertę - pełne opcje GC pokazały mi, że próbuje zbierać śmieci, ale bezskutecznie. W debugerze mogłem wykonać System.gc () i na pewno byłoby „dużo” dostępnej pamięci ... niewiele dodatkowej, ale wystarczającej.
W rezultacie moja aplikacja wywołuje System.gc () tylko wtedy, gdy ma zamiar wejść do segmentu kodu, w którym zostaną przydzielone duże bufory niezbędne do przetwarzania danych, a test na dostępnej wolnej pamięci wskazuje, że nie gwarantujemy to. W szczególności patrzę na środowisko 1 GB, w którym co najmniej 300 MB jest zajmowane przez dane statyczne, przy czym większość danych niestatycznych jest związanych z wykonywaniem, z wyjątkiem sytuacji, gdy przetwarzane dane mają co najmniej 100-200 MB w źródło. To wszystko jest częścią procesu automatycznej konwersji danych, więc dane istnieją przez stosunkowo krótki czas w dłuższej perspektywie.
Niestety, chociaż dostępne są informacje o różnych opcjach strojenia garbage collectora, wydaje się, że jest to w dużej mierze proces eksperymentalny, a szczegóły niższego poziomu potrzebne do zrozumienia, jak radzić sobie z tymi konkretnymi sytuacjami, nie są łatwe.
Wszystko to zostało powiedziane, mimo że używam System.gc (), nadal dostrajałem się za pomocą parametrów wiersza poleceń i udało mi się poprawić ogólny czas przetwarzania mojej aplikacji o stosunkowo znaczną ilość, mimo że nie mogłem obejść przeszkodą wynikającą z pracy z większymi blokami danych. Biorąc to pod uwagę, System.gc () jest narzędziem ... bardzo zawodnym narzędziem, a jeśli nie jesteś ostrożny z tym, jak go używasz, będziesz żałować, że nie działało częściej niż nie.
źródło
Jeśli chcesz wiedzieć, czy ktoś dzwoni do Ciebie
System.gc()
, dzięki nowej aktualizacji 4 oprogramowania Java 7 możesz otrzymać powiadomienie, gdy JVM przeprowadza czyszczenie pamięci.Nie jestem jednak w 100% pewien, że klasa GarbageCollectorMXBean została wprowadzona w aktualizacji 4 Java 7, ponieważ nie mogłem jej znaleźć w informacjach o wydaniu, ale znalazłem informacje w witrynie javaperformancetuning .com
źródło
Nie przychodzi mi do głowy konkretny przykład, kiedy dobrze jest uruchomić jawny GC.
Ogólnie rzecz biorąc, uruchomienie jawnego GC może w rzeczywistości spowodować więcej szkody niż pożytku, ponieważ jawne GC wyzwoli pełną kolekcję, która trwa znacznie dłużej, ponieważ przechodzi przez każdy obiekt. Jeśli ten jawny gc zostanie wywołany wielokrotnie, może to łatwo doprowadzić do spowolnienia aplikacji, ponieważ spędza dużo czasu na uruchamianiu pełnych GC.
Alternatywnie, jeśli przeglądasz stertę za pomocą analizatora sterty i podejrzewasz, że komponent biblioteki wywołuje jawne GC, możesz go wyłączyć, dodając: gc = -XX: + DisableExplicitGC do parametrów JVM.
źródło
Zgodnie z Thinking in Java Bruce Eckel, jeden przypadek użycia dla jawnego System.gc () wywołania jest wymuszenie finalizacji, czyli wywołanie metody finalize .
źródło
podczas gdy system.gc działa, zatrzyma świat: wszystkie odpowiedzi są zatrzymywane, więc garbage collector może przeskanować każdy obiekt, aby sprawdzić, czy jest potrzebny usunięty. jeśli aplikacja jest projektem sieciowym, wszystkie żądania są zatrzymywane do zakończenia działania gc, co spowoduje, że projekt sieciowy nie będzie działał w trybie monenta.
źródło