Muszę wiedzieć, kiedy finalize()
metoda jest wywoływana w JVM
. Utworzyłem klasę testową, która zapisuje do pliku, gdy finalize()
metoda jest wywoływana przez przesłonięcie go. To nie jest wykonywane. Czy ktoś może mi powiedzieć, dlaczego nie jest wykonywany?
330
finalize()
a odśmiecanie nie ma żadnego wpływu.Odpowiedzi:
Ogólnie najlepiej nie polegać na
finalize()
czyszczeniu itp.Według Javadoc (które warto przeczytać) jest to:
Jak zauważył Joachim, może się to nigdy nie wydarzyć w życiu programu, jeśli obiekt jest zawsze dostępny.
Ponadto nie można zagwarantować, że moduł wyrzucania elementów bezużytecznych zostanie uruchomiony w określonym momencie. Ogólnie rzecz biorąc, to, co próbuję powiedzieć, to
finalize()
prawdopodobnie nie jest najlepsza metoda do zastosowania w ogóle, chyba że potrzebujesz czegoś konkretnego.źródło
finalize
przydałaby się?finalize()
Metoda na na głównej klasy jest wywoływana gdy << >> instancja klasy jest śmieci zbierane, gdy główny nie zakończone jest metoda. Poza tym główną klasą mogą być śmieci wyrzucane przed zakończeniem aplikacji; np. w aplikacji wielowątkowej, w której wątek „główny” tworzy inne wątki, a następnie powraca. (W praktyce wymagany byłby niestandardowy moduł ładujący klasy ...)finalize
Metoda jest wywoływana, gdy obiekt ma zamiar uzyskać śmieci zebrane. Może to nastąpić w dowolnym momencie po zakwalifikowaniu do zbierania śmieci.Zauważ, że jest całkowicie możliwe, że obiekt nigdy nie zostanie wyrzucony śmieci (a zatem
finalize
nigdy nie zostanie wywołany). Może się to zdarzyć, gdy obiekt nigdy nie kwalifikuje się do gc (ponieważ jest osiągalny przez cały okres istnienia maszyny JVM) lub gdy żadne czyszczenie pamięci nie działa w rzeczywistości między momentem, w którym obiekt staje się kwalifikujący, a czasem, w którym maszyna JVM przestaje działać (często dzieje się tak z prostym programy testowe).Istnieją sposoby, aby JVM działał
finalize
na obiektach, które nie zostały jeszcze wywołane, ale użycie ich również nie jest dobrym pomysłem (gwarancje tej metody też nie są zbyt silne).Jeśli polegasz na
finalize
poprawnym działaniu aplikacji, robisz coś złego.finalize
powinien być używany tylko do czyszczenia zasobów (zwykle innych niż Java). A to właśnie dlatego, że JVM nie gwarantuje, żefinalize
kiedykolwiek zostanie wywołany na dowolnym obiekcie.źródło
Closable
interfejs (i idea) jest prawdopodobnie tym, czego chcesz:.close()
zamknij / odrzuć zasób i wymagaj, aby użytkownik twojej klasy zadzwonił do niego we właściwym czasie. Ty może chcesz dodaćfinalize
metodę „po prostu się Zapisz”, ale to byłoby raczej narzędzie do debugowania niż rzeczywistej fix (ponieważ nie jest wystarczająco wiarygodne).System.gc()
aby wywołać funkcję FileInputStream :: finalize (), a następnie mogłem przenieść plik.cytowany z: http://www.janeg.ca/scjp/gc/finalize.html
Możesz również sprawdzić ten artykuł:
źródło
Metoda Java
finalize()
nie jest destruktorem i nie powinna być używana do obsługi logiki, od której zależy twoja aplikacja. Zgodnie ze specyfikacją Java nie ma żadnej gwarancji, żefinalize
metoda zostanie w ogóle wywołana podczas życia aplikacji.Prawdopodobnie chcesz kombinacji
finally
i metody czyszczenia, jak w:źródło
Sprawdź Effective Java, wydanie drugie, strona 27. Punkt 7: Unikaj finalizatorów
Aby zakończyć zasób, użyj zamiast tego try-last:
źródło
Metoda finalizacji zostanie wywołana, gdy GC wykryje, że obiekt nie jest już osiągalny, i zanim faktycznie odzyska pamięć używaną przez obiekt.
Jeśli obiekt nigdy nie stanie się nieosiągalny,
finalize()
nigdy nie zostanie do niego wezwany.Jeśli GC nie działa,
finalize()
może nigdy nie zostać wywołany. (Zwykle GC działa tylko wtedy, gdy JVM zdecyduje, że istnieje wystarczająca ilość śmieci, aby było warto.)Może upłynąć więcej niż jeden cykl GC, zanim GC ustali, że określony obiekt jest nieosiągalny. (GC Java to zwykle kolektory „generacyjne” ...)
Gdy GC wykryje, że obiekt jest nieosiągalny i możliwy do finalizacji, umieszcza się w kolejce finalizacji. Finalizacja zwykle odbywa się asynchronicznie z normalnym GC.
(Specyfikacja JVM faktycznie pozwala JVM nigdy nie uruchamiać finalizatorów ... pod warunkiem, że nie odzyskuje miejsca używanego przez obiekty. JVM, który został zaimplementowany w ten sposób, zostałby okaleczony / bezużyteczny, ale takie zachowanie jest „dozwolone” .)
Rezultatem jest to, że nierozsądne jest poleganie na finalizacji, aby robić rzeczy, które muszą być wykonane w określonych ramach czasowych. „Najlepszą praktyką” jest nieużywanie ich wcale. Powinien istnieć lepszy (tj. Bardziej niezawodny) sposób robienia tego, co próbujesz zrobić w
finalize()
metodzie.Jedynym uzasadnionym zastosowaniem do finalizacji jest oczyszczenie zasobów związanych z obiektami utraconymi przez kod aplikacji. Nawet wtedy powinieneś spróbować napisać kod aplikacji, aby nie stracił obiektów w pierwszej kolejności. (Na przykład użyj Java try-try-with-resources, aby mieć pewność, że
close()
zawsze jest wywoływana ...)Trudno powiedzieć, ale jest kilka możliwości:
źródło
Ponieważ w JVM występuje niepewność w wywoływaniu metody finalize () (nie wiadomo, czy przesłonięta zostanie finalizowana (), czy nie), dla celów badania lepszym sposobem na zaobserwowanie, co się dzieje, gdy wywoływana jest metoda finalize (), jest zmusza JVM do wywoływania funkcji odśmiecania za pomocą polecenia
System.gc()
.W szczególności funkcja finalize () jest wywoływana, gdy obiekt nie jest już używany. Ale kiedy próbujemy to nazwać, tworząc nowe obiekty, nie ma pewności co do jego wywołania. Dlatego dla pewności tworzymy
null
obiekt,c
który oczywiście nie będzie w przyszłości wykorzystywany, dlatego widzimyc
wywołanie finalizacji obiektu.Przykład
Wynik
Uwaga - Nawet po wydrukowaniu do 70 i po tym, gdy obiekt b nie jest używany w programie, nie ma pewności, czy JVM jest usuwany, czy nie, ponieważ „Wywołana metoda finalizacji w klasie Bike ...” nie jest drukowana.
źródło
System.gc();
nie jest gwarancją, że wyrzucanie elementów bezużytecznych zostanie uruchomione.sfinalizuj wydrukuje licznik tworzenia klasy.
Główny
Jak widzisz. Poniższy przykład pokazuje, że gc został wykonany po raz pierwszy, gdy liczba klas wynosi 36.
źródło
Ostatnio zmagając się z metodami finalizatora (aby pozbyć się puli połączeń podczas testowania), muszę powiedzieć, że finalizatorowi brakuje wielu rzeczy. Używając VisualVM do obserwacji, a także używając słabych referencji do śledzenia faktycznej interakcji, stwierdziłem, że następujące rzeczy są prawdziwe w środowisku Java 8 (Oracle JDK, Ubuntu 15):
Końcowa myśl
Metoda finalizacji jest niewiarygodna, ale można jej użyć tylko do jednej rzeczy. Możesz upewnić się, że obiekt został zamknięty lub usunięty przed zbieraniem śmieci, dzięki czemu można zaimplementować zabezpieczenie przed awarią, jeśli obiekty o bardziej złożonym cyklu życia obejmujące akcję wycofania z eksploatacji są obsługiwane poprawnie. To jedyny powód, dla którego mogę to wymyślić, dlatego warto to zmienić.
źródło
Obiekt kwalifikuje się do wyrzucania elementów bezużytecznych lub GC, jeśli nie jest osiągalny z żadnych aktywnych wątków lub jakichkolwiek statycznych odwołań, innymi słowy, można powiedzieć, że obiekt kwalifikuje się do wyrzucania elementów bezużytecznych, jeśli wszystkie odniesienia są zerowe. Zależności cykliczne nie są liczone jako referencje, więc jeśli obiekt A ma referencję do obiektu B, a obiekt B ma referencję do obiektu A i nie mają żadnych innych aktywnych referencji, wówczas zarówno obiekty A, jak i B będą kwalifikowały się do odśmiecania. Zasadniczo obiekt kwalifikuje się do wyrzucania elementów bezużytecznych w Javie w następujących przypadkach:
źródło
final
pole obiektu jest używane wielokrotnie podczas powolnego obliczania, a obiekt nigdy nie będzie później używany, obiekt pozostanie przy życiu, dopóki kod źródłowy nie zażąda tego pola, lub JIT może skopiować pole do zmienna tymczasowa, a następnie porzucić obiekt przed obliczeniami?GC.KeepAlive()
funkcja, która nic nie robi poza zmuszeniem GC do założenia, że może użyć obiektu, ale nie znam żadnej takiej funkcji w Javie. Można użyćvolatile
zmiennej do tego celu, ale użycie zmiennej wyłącznie do takiego celu wydaje się marnotrawstwem.FinalizerReference
, aby nie potrzebował cyklu GC, aby dowiedzieć się, że nie ma Bibliografia. Synchronizacja jest wystarczająca, aby zapewnić relację przed zdarzeniem; ponieważ finalizacja może (faktycznie jest) przebiegać w innym wątku, i tak często jest to formalnie konieczne. Java 9 dodaReference.reachabilityFence
…Finalize
ogóle zostanie wywołane, jeśli JIT wytworzy kod, który zrobił to bezpośrednio. Czy kod synchronizacji jest zwykle oczekiwany dla obiektów, które mają być używane tylko w jednym wątku? Jeśli obiekt wykonuje jakąś akcję, którą należy cofnąć, zanim zostanie porzucony (np. Otwarcie połączenia z gniazdem i uzyskanie wyłącznego użytku z zasobem na drugim końcu), zamknięcie połączenia przez finalizator, gdy kod nadal korzysta z gniazda, byłoby katastrofą . Czy to normalne, że kod korzysta z synchronizacji ...metoda finalizacji nie jest gwarantowana. Ta metoda jest wywoływana, gdy obiekt kwalifikuje się do GC. Istnieje wiele sytuacji, w których obiekty nie mogą być śmieciami.
źródło
Czasami, gdy zostanie zniszczony, obiekt musi wykonać akcję. Na przykład, jeśli obiekt ma zasób inny niż Java, taki jak uchwyt pliku lub czcionka, możesz sprawdzić, czy zasoby te zostały zwolnione przed zniszczeniem obiektu. Aby poradzić sobie z takimi sytuacjami, Java oferuje mechanizm zwany „finalizowaniem”. Finalizując go, możesz zdefiniować określone akcje, które będą miały miejsce, gdy obiekt ma zostać usunięty z pojemnika na śmieci. Aby dodać finalizator do klasy, po prostu zdefiniuj metodę finalize () . Czas wykonania Java wywołuje tę metodę za każdym razem, gdy ma zamiar usunąć obiekt tej klasy. W ramach metody finalizacji ()określasz akcje do wykonania przed zniszczeniem obiektu. Moduł czyszczący jest okresowo przeszukiwany pod kątem obiektów, które nie odnoszą się już do żadnego stanu działania lub pośrednio do jakiegokolwiek innego obiektu z odniesieniem. Przed zwolnieniem zasobu środowisko wykonawcze Java wywołuje metodę finalize () na obiekcie. Metoda finalize () ma następującą ogólną formę:
Dzięki chronionemu słowu kluczowemu dostęp do finalize () według kodu poza jego klasą jest uniemożliwiony. Ważne jest, aby zrozumieć, że funkcja finalize () jest wywoływana tuż przed wyrzucaniem elementów bezużytecznych. Na przykład nie jest wywoływany, gdy obiekt opuszcza zakres. Oznacza to, że nie możesz wiedzieć, kiedy lub czy zostanie wykonana finalizacja () . W rezultacie program musi zapewnić inne środki do zwolnienia zasobów systemowych lub innych zasobów używanych przez obiekt. Nie powinieneś polegać na finalize () do normalnego działania programu.
źródło
Klasa, w której zastępujemy metodę finalizacji
Szanse na wywołanie metody finalizacji
gdy pamięć jest przeciążona obiektami zrzutu, gc wywoła metodę finalizacji
uruchom i zobacz konsolę, w której często nie wywołuje się metody finalizacji, gdy pamięć jest przeciążana, wówczas wywoływana jest metoda finalizacji.
źródło
Źródło
źródło
finalize()
nazywa się tuż przed odśmiecaniem pamięci. Nie jest wywoływany, gdy obiekt wykracza poza zakres. Oznacza to, że nie możesz wiedzieć, kiedy, a nawet czyfinalize()
zostanie wykonany.Przykład:
Jeśli program zakończy się przed wystąpieniem modułu czyszczenia
finalize()
pamięci, nie zostanie wykonany. Dlatego należy go stosować jako procedurę tworzenia kopii zapasowej w celu zapewnienia właściwego obchodzenia się z innymi zasobami lub w aplikacjach specjalnego użytku, a nie jako środek wykorzystywany przez program podczas normalnej pracy.źródło
Jak wskazano w https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,
źródło
Spróbuj zepsuć ten program, aby lepiej zrozumieć
źródło