Czy można wymusić zbieranie śmieci w Javie, nawet jeśli jest to trudne? Znam System.gc();
i Runtime.gc();
ale tylko proponuję zrobić GC. Jak mogę zmusić GC?
Czy można wymusić zbieranie śmieci w Javie, nawet jeśli jest to trudne? Znam System.gc();
i Runtime.gc();
ale tylko proponuję zrobić GC. Jak mogę zmusić GC?
Odpowiedzi:
Najlepszą opcją jest wywołanie, System.gc()
które jest po prostu wskazówką dla śmieciarza, że ma on wykonywać kolekcję. Nie ma jednak sposobu na wymuszenie i natychmiastowe pobranie, ponieważ śmieciarz nie jest deterministyczny.
non-deterministic == trouble
GC.Collect()
nie zbiera. W Javie gc()
robi.
Biblioteka jlibs ma dobrą klasę użytkową do zbierania śmieci . Możesz wymusić wyrzucanie elementów bezużytecznych przy użyciu sprytnej sztuczki z obiektami WeakReference .
RuntimeUtil.gc () z jlibs:
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
z, ReferenceQueue
a następnie otrzymasz powiadomienie po zakończeniu, ale jeszcze przed czyszczeniem. Wreszcie, nawet jeśli uda się wykryć, że pamięć dla tego obiektu została odzyskana, nadal będzie to miało bardzo małe znaczenie w generacyjnej GC, takiej jak HotSpot. Zwykle zbiega się to w czasie z porządkiem młodego pokolenia.
System.gc(); System.gc();
, ale na pewno byłoby interesujące wiedzieć, czy kiedykolwiek zadziałałoby lepiej. W rzeczywistości wystarczy wydrukować, ile razy był wywoływany System.gc()
. Szansa na osiągnięcie 2 jest dość niewielka.
Najlepszym (jeśli nie tylko) sposobem wymuszenia GC byłoby napisanie niestandardowej maszyny JVM. Wierzę, że Garbage collectors można podłączyć, więc prawdopodobnie możesz po prostu wybrać jedną z dostępnych implementacji i dostosować ją.
Uwaga: To NIE jest łatwa odpowiedź.
Korzystanie z Java ™ Virtual Machine Interface Tool (JVM Ti) , funkcja
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
„Zmusi maszynę wirtualną do wyrzucania elementów bezużytecznych”. Interfejs JVM TI jest częścią architektury debugera platformy JavaTM (JPDA) .
TAK , prawie można zmusić cię do wywoływania metod w tej samej kolejności, a jednocześnie są to:
System.gc ();
System.runFinalization ();
nawet jeśli jest to tylko jeden obiekt do wyczyszczenia przy użyciu tych dwóch metod jednocześnie, zmuś śmieciarz do użycia finalise()
metody nieosiągalnego obiektu, zwalniając przydzieloną pamięć i wykonując czynności podane przez finalize()
metodę.
JEDNAK to okropna praktyka korzystania z modułu wyrzucania elementów bezużytecznych, ponieważ użycie go może spowodować nadmierne obciążenie oprogramowania, które może być nawet gorsze niż w przypadku pamięci, moduł wyrzucający elementy ma własny wątek, którego nie można kontrolować plus w zależności od algorytm używany przez gc może zająć więcej czasu i jest uważany za bardzo nieefektywny, powinieneś sprawdzić swoje oprogramowanie, jeśli jest najgorsze z pomocą gc, ponieważ jest zdecydowanie zepsuty, dobre rozwiązanie nie może zależeć od gc.
UWAGA: aby pamiętać, będzie to działało tylko wtedy, gdy w metodzie finalizacji nie nastąpi zmiana przypisania obiektu, jeśli tak się stanie, obiekt pozostanie przy życiu i będzie miał zmartwychwstanie, które jest technicznie możliwe.
gc()
jest tylko wskazówką do uruchomienia śmiecia. runFinalizers()
uruchamia finalizatory tylko na obiektach „uznanych za odrzucone”. Jeśli GC tak naprawdę nie uruchomił się, może nie być takich obiektów ...
W dokumentacji OutOfMemoryError oświadcza, że nie zostanie wyrzucony, dopóki maszyna wirtualna nie odzyska pamięci po pełnym wyrzucaniu elementów bezużytecznych. Więc jeśli będziesz nadal alokował pamięć, dopóki nie pojawi się błąd, już wymusiłeś pełne odśmiecanie.
Przypuszczalnie pytanie, które naprawdę chciałeś zadać, brzmiało: „jak mogę odzyskać pamięć, myślę, że powinienem ją odzyskać poprzez zbieranie śmieci?”.
Aby ręcznie zażądać GC (nie z System.gc ()):
.gc jest kandydatem do eliminacji w przyszłych wydaniach - inżynier Sun powiedział kiedyś, że może mniej niż dwadzieścia osób na świecie faktycznie umie używać .gc () - Pracowałem wczoraj przez kilka godzin nad centralnym / krytycznym struktura danych z wykorzystaniem danych wygenerowanych przez SecureRandom, gdzieś tuż ponad 40 000 obiektów vm zwolniłoby, jakby zabrakło wskaźników. Najwyraźniej dławił się 16-bitowymi tabelami wskaźników i wykazywał klasyczne zachowanie „niesprawnej maszynerii”.
Próbowałem -Xms i tak dalej, trochę kręciłem się, dopóki nie skończyło się to około 57, xxx czegoś. Następnie uruchomiłoby gc, zaczynając od powiedzmy 57 127 do 57 128 po gc () - w przybliżeniu w tempie rozdętego kodu w obozie Easy Money.
Twój projekt wymaga gruntownej przeróbki, prawdopodobnie podejścia z przesuwanym oknem.
Możesz uruchomić GC z wiersza poleceń. Jest to przydatne dla partii / crontab:
jdk1.7.0/bin/jcmd <pid> GC.run
Widzieć :
Specyfikacja JVM nie mówi nic konkretnego o odśmiecaniu. Z tego powodu dostawcy mogą swobodnie wdrażać GC na swój sposób.
Tak więc ta niejasność powoduje niepewność w zachowaniu podczas wyrzucania elementów bezużytecznych. Powinieneś sprawdzić swoje dane JVM, aby wiedzieć o podejściach / algorytmach czyszczenia pamięci. Istnieją również opcje dostosowywania zachowania.
Jeśli chcesz wymusić wyrzucanie elementów bezużytecznych, być może powinieneś rozważyć sposób zarządzania zasobami. Czy tworzysz duże obiekty, które pozostają w pamięci? Czy tworzysz duże obiekty (np. Klasy graficzne), które mają Disposable
interfejs i nie wywołują go dispose()
po zakończeniu ? Czy deklarujesz coś na poziomie klasy, czego potrzebujesz tylko w ramach jednej metody?
Byłoby lepiej, gdybyś opisał powód, dla którego potrzebujesz zbierania śmieci. Jeśli używasz SWT, możesz pozbyć się zasobów takich jak Image
i Font
zwolnić pamięć. Na przykład:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Istnieją również narzędzia do określania niewykorzystanych zasobów.
Jeśli kończy Ci się pamięć i dostajesz OutOfMemoryException
, możesz spróbować zwiększyć ilość sterty dostępnej dla java, uruchamiając program java -Xms128m -Xmx512m
zamiast zamiast java
. To da ci początkową wielkość sterty 128 Mb i maksymalnie 512 Mb, czyli znacznie więcej niż standardowe 32 Mb / 128 Mb.
java -Xms512M -Xmx1024M
Inną opcją jest nie tworzenie nowych obiektów.
Buforowanie obiektów jest niedostępne , aby zmniejszyć potrzebę GC w Javie.
Pula obiektów na ogół nie będzie szybsza niż tworzenie obiektów (szczególnie w przypadku lekkich obiektów), ale jest szybsza niż odśmiecanie. Jeśli utworzono 10 000 obiektów, a każdy obiekt miał 16 bajtów. To 160 000 bajtów, które GC musi odzyskać. Z drugiej strony, jeśli nie potrzebujesz wszystkich 10 000 jednocześnie, możesz utworzyć pulę do recyklingu / ponownego wykorzystania obiektów, co eliminuje potrzebę konstruowania nowych obiektów i eliminuje potrzebę GC starych obiektów.
Coś takiego (nieprzetestowane). A jeśli chcesz, aby był wątkowo bezpieczny, możesz zamienić LinkedList na ConcurrentLinkedQueue.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
Na OracleJDK 10 z G1 GC, pojedyncze wywołanie System.gc()
spowoduje, że GC wyczyści Starą Kolekcję. Nie jestem pewien, czy GC działa natychmiast. Jednak GC nie posprząta Young Collection, nawet jeśli System.gc()
jest wywoływany wiele razy w pętli. Aby GC wyczyścił Young Collection, musisz przydzielić w pętli (np. new byte[1024]
) Bez wywoływania System.gc()
. Dzwonienie System.gc()
z jakiegoś powodu uniemożliwia GC oczyszczenie kolekcji Young.
Naprawdę nie rozumiem cię. Ale żeby być jasnym na temat „Infinite Object Creation”, miałem na myśli, że w moim wielkim systemie jest jakiś fragment kodu do tworzenia obiektów, które obsługują i żyją w pamięci, nie mogłem dostać tego fragmentu kodu, tylko gest !!
To jest poprawne, tylko gest. Masz prawie standardowe odpowiedzi podane już przez kilka plakatów. Weźmy to jeden po drugim:
Zgadza się, nie ma rzeczywistego jvm - taka jest tylko specyfikacja, garść informatyki opisująca pożądane zachowanie ... Niedawno zacząłem inicjować obiekty Java z kodu natywnego. Aby uzyskać to, czego chcesz, jedynym sposobem jest wykonanie agresywnego zerowania. Błędy, jeśli popełnione źle, są tak złe, że musimy ograniczyć się do pierwotnego zakresu pytania:
Większość plakatów tutaj zakłada, że mówisz, że pracujesz nad interfejsem, jeśli tak, będziemy musieli sprawdzić, czy otrzymujesz cały obiekt czy jeden element na raz.
Jeśli nie potrzebujesz już obiektu, możesz przypisać do niego wartość NULL, ale jeśli się pomylisz, wygenerowany zostanie wyjątek wskaźnika NULL. Założę się, że możesz osiągnąć lepszą pracę, jeśli używasz NIO
Za każdym razem, gdy ty, ja lub ktokolwiek inny dostaje: „ Proszę, potrzebuję tego okropnie. ” Jest to prawie uniwersalny prekursor prawie całkowitego zniszczenia tego, nad czym próbujesz pracować ... napisz do nas mały przykładowy kod, odkażając go użyty kod i pokaż nam swoje pytanie.
Nie denerwuj się. Często rozwiązuje to problem z tym, że dba używa pakietu kupionego gdzieś, a oryginalny projekt nie jest dostosowany do ogromnych struktur danych.
To jest bardzo powszechne.
Do Twojej wiadomości
Wywołanie metody System.runFinalizersOnExit (true) gwarantuje, że metody finalizatora zostaną wywołane przed zamknięciem Java. Jednak ta metoda jest z natury niebezpieczna i została uznana za przestarzałą. Alternatywą jest dodanie „haków zamykania” za pomocą metody Runtime.addShutdownHook.
Masarrat Siddiqui
Istnieje jakiś pośredni sposób na wymuszenie śmieciarza. Musisz tylko wypełnić stertę obiektami tymczasowymi, aż do momentu, w którym uruchomi się moduł czyszczenia pamięci. Stworzyłem klasę, która wymusza w ten sposób zbieranie śmieci:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Stosowanie:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Nie wiem, jak bardzo ta metoda jest przydatna, ponieważ stale wypełnia stertę, ale jeśli masz krytyczną aplikację, która MUSI wymusić GC - kiedy może to być przenośny sposób na wymuszenie GC w Javie.
Chciałbym tu coś dodać. Należy pamiętać, że Java nie działa na maszynie wirtualnej, a nie na rzeczywistej maszynie. Maszyna wirtualna ma swój własny sposób komunikacji z maszyną. Może różnić się w zależności od systemu. Teraz, gdy dzwonimy do GC, prosimy Wirtualną Maszynę Javy o wywołanie Garbage Collector.
Ponieważ Garbage Collector jest wyposażony w maszynę wirtualną, nie możemy zmusić go do przeprowadzenia czyszczenia tam i wtedy. Zamiast tego ustawiamy w kolejce nasze żądanie do Garbage Collector. Zależy to od maszyny wirtualnej, po określonym czasie (może się to zmieniać z systemu na system, zwykle gdy pamięć progowa przydzielona do JVM jest pełna), rzeczywista maszyna zwolni miejsce. :RE
Poniższy kod pochodzi z metody assertGC (...). Próbuje zmusić niedeterministyczny kolektor śmieci do zbierania.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
Źródło (dodałem kilka komentarzy dla jasności): Przykład NbTestCase
Możesz spróbować użyć Runtime.getRuntime().gc()
lub użyć metody narzędzia System.gc()
Uwaga: Te metody nie zapewniają GC. Ich zakres powinien być ograniczony do JVM, a nie programowo obsługiwać go w aplikacji.