Czy istnieje sposób na zwolnienie pamięci w Javie, podobny do free()
funkcji C ? A może ustawienie obiektu na wartość null i poleganie na GC to jedyna opcja?
java
garbage-collection
Felix
źródło
źródło
Odpowiedzi:
Java korzysta z pamięci zarządzanej, więc jedynym sposobem przydzielenia pamięci jest użycie
new
operatora, a jedynym sposobem na zwolnienie pamięci jest użycie modułu odśmiecania pamięci.To zarządzanie pamięcią oficjalny dokument (PDF) może pomóc wyjaśnić, co się dzieje.
Możesz również zadzwonić,
System.gc()
aby zasugerować natychmiastowe uruchomienie modułu odśmiecania pamięci. Jednak ostateczną decyzję podejmuje Java Runtime, a nie kod.Zgodnie z dokumentacją Java ,
źródło
System.gc()
całkowicie ignorują .Wydaje się, że nikt nie wspomniał wprost o ustawianiu odniesień do obiektów
null
, co jest uzasadnioną techniką „zwalniania” pamięci, którą warto rozważyć.Na przykład, załóżmy, że zadeklarowałeś
List<String>
na początku metody, która rozrosła się i była bardzo duża, ale była wymagana tylko do połowy metody. W tym momencie można ustawić odwołanie do listy,null
aby umożliwić modułowi wyrzucania elementów bezużytecznych potencjalnie odzyskanie tego obiektu przed zakończeniem metody (i mimo to odwołanie wykracza poza zakres).Zauważ, że w rzeczywistości rzadko używam tej techniki, ale warto to rozważyć, gdy mam do czynienia z bardzo dużymi strukturami danych.
źródło
Niepolecane.
Edycja: napisałem oryginalną odpowiedź w 2009 roku. Jest teraz 2015.
Urządzenia do usuwania śmieci stawały się coraz lepsze w ciągu ~ 20 lat istnienia Java. W tym momencie, jeśli ręcznie wywołujesz moduł odśmiecania pamięci, możesz rozważyć inne podejścia:
źródło
* „Osobiście polegam na zerowaniu zmiennych jako symbolu zastępczego dla przyszłego prawidłowego usunięcia. Na przykład, poświęcam trochę czasu, aby anulować wszystkie elementy tablicy przed faktycznym usunięciem (nadaniem wartości zerowej) samej tablicy.”
To jest niepotrzebne. Sposób działania Java GC polega na tym, że znajduje obiekty, które nie mają do nich odniesienia, więc jeśli mam obiekt x z odwołaniem (= zmienną) a, które na niego wskazuje, GC go nie usunie, ponieważ istnieje odniesienie do tego obiektu:
Jeśli wyzerujesz a, to się stanie:
Więc teraz x nie ma odniesienia do niego wskazującego i zostanie usunięte. To samo dzieje się, gdy ustawisz a jako odniesienie do innego obiektu niż x.
Więc jeśli masz tablicę arr, która odwołuje się do obiektów x, y i z oraz zmienną a, która odwołuje się do tablicy, wygląda to tak:
Jeśli wyzerujesz a, to się stanie:
Więc GC znajduje arr, który nie ma ustawionego odniesienia i usuwa go, co daje następującą strukturę:
Teraz GC znajduje x, y i z i usuwa je również. Zerowanie każdego odniesienia w tablicy nie poprawi niczego, po prostu zużyje czas procesora i miejsce w kodzie (to powiedziawszy, nie zaszkodzi bardziej niż to. GC nadal będzie w stanie działać tak, jak powinien) ).
źródło
Ważnym powodem chęci zwolnienia pamięci z dowolnego programu (java lub nie) jest udostępnienie większej ilości pamięci innym programom na poziomie systemu operacyjnego. Jeśli moja aplikacja java używa 250 MB, mogę chcieć zmniejszyć ją do 1 MB i udostępnić 249 MB innym aplikacjom.
źródło
Aby rozszerzyć odpowiedź i komentarz Yiannisa Xanthopoulosa i Hot Licks (przepraszam, nie mogę jeszcze komentować!), Możesz ustawić opcje maszyny wirtualnej w następujący sposób:
W moim jdk 7 spowoduje to zwolnienie nieużywanej pamięci maszyny wirtualnej, jeśli ponad 30% sterty zostanie zwolnione po GC, gdy maszyna wirtualna jest bezczynna. Prawdopodobnie będziesz musiał dostroić te parametry.
Chociaż nie widziałem tego podkreślonego w linku poniżej, zauważ, że niektóre garbage collectors mogą nie przestrzegać tych parametrów i domyślnie java może wybrać jeden z nich, jeśli masz więcej niż jeden rdzeń (stąd powyższy argument UseG1GC ).
Argumenty maszyny wirtualnej
Aktualizacja: W przypadku Java 1.8.0_73 widziałem, jak JVM od czasu do czasu wypuszczał niewielkie kwoty z domyślnymi ustawieniami. Wydaje się, że robi to tylko wtedy, gdy ~ 70% sterty jest nieużywanych .. nie wiem, czy zwolnienie byłoby bardziej agresywne, gdyby system operacyjny miał mało pamięci fizycznej.
źródło
Zrobiłem na tym eksperymenty.
To prawda, że
System.gc();
tylko sugeruje uruchomienie garbage collectora.Ale wywołanie
System.gc();
po ustawieniu wszystkich odniesień nanull
, poprawi wydajność i wykorzystanie pamięci.źródło
Jeśli naprawdę chcesz przydzielić i zwolnić blok pamięci, możesz to zrobić za pomocą bezpośrednich ByteBuffers. Istnieje nawet nieprzenośny sposób na zwolnienie pamięci.
Jednak, jak zasugerowano, tylko dlatego, że musisz zwolnić pamięć w C, nie oznacza, że warto to zrobić.
Jeśli uważasz, że naprawdę masz dobry przypadek użycia za darmo (), uwzględnij go w pytaniu, abyśmy mogli zobaczyć, co zamierzasz zrobić, jest całkiem prawdopodobne, że istnieje lepszy sposób.
źródło
W całości z javacoffeebreak.com/faq/faq0012.html
źródło
W moim przypadku, ponieważ mój kod Java ma zostać przeniesiony na inne języki w niedalekiej przyszłości (głównie C ++), przynajmniej chcę zapłacić frazę za prawidłowe zwolnienie pamięci, aby pomóc później w procesie przenoszenia.
Osobiście polegam na zerowaniu zmiennych jako symbolu zastępczym dla przyszłego prawidłowego usunięcia. Na przykład poświęcam trochę czasu, aby unieważnić wszystkie elementy tablicy, zanim faktycznie usunę (uczynię null) samą tablicę.
Ale mój przypadek jest bardzo szczególny i wiem, że robiąc to, odbieram hity wydajności.
źródło
* „Na przykład, powiedzmy, że zadeklarowałeś List na początku metody, która rozrosła się i stała się bardzo duża, ale była wymagana tylko do połowy metody. W tym momencie możesz ustawić odwołanie List na wartość null aby umożliwić modułowi odśmiecania pamięci potencjalnie odzyskanie tego obiektu przed zakończeniem metody (a odwołanie i tak wykracza poza zakres). " *
To prawda, ale tego rozwiązania nie da się uogólnić. Podczas ustawiania odwołania do obiektu List na null -will- udostępni pamięć do czyszczenia pamięci, jest to prawdą tylko dla obiektu List typów pierwotnych. Jeśli zamiast tego obiekt List zawiera typy odwołań, ustawienie obiektu List = null nie spowoduje wyłuskiwania -dowolnych- typów odwołań zawartych na liście. W takim przypadku ustawienie obiektu List = null spowoduje osierocenie zawartych typów odwołań, których obiekty nie będą dostępne do czyszczenia pamięci, chyba że algorytm czyszczenia pamięci jest wystarczająco inteligentny, aby określić, że obiekty zostały osierocone.
źródło
Chociaż java zapewnia automatyczne czyszczenie pamięci czasami będziesz chciał wiedzieć, jak duży jest obiekt i ile go pozostało. Zwolnij pamięć używając programowo
import java.lang;
iRuntime r=Runtime.getRuntime();
aby uzyskać wartości pamięci używającmem1=r.freeMemory();
do zwolnienia pamięci wywołajr.gc();
metodę i wywołaniefreeMemory()
źródło
Rekomendacją z JAVA jest przypisanie do null
Z https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
źródło