Czy pola statyczne są otwarte do czyszczenia pamięci?

96

Biorąc pod uwagę hipotetyczną klasę narzędziową, która jest używana tylko w konfiguracji programu:

class MyUtils {
   private static MyObject myObject = new MyObject();
   /*package*/static boolean doStuff(Params... params) {
       // do stuff with myObject and params...
   }
}

czy myObject będzie zbierany jako śmieci, gdy nie będzie już używany, czy też pozostanie przez całe życie programu?

Michael Deardeuff
źródło

Odpowiedzi:

113

Nie można wybrać zmiennych statycznych do czyszczenia pamięci podczas ładowania klasy. Można je zebrać, gdy odpowiedni program ładujący klasy (który był odpowiedzialny za załadowanie tej klasy) sam jest zbierany do śmieci.

Zapoznaj się z sekcją JLS 12.7 Rozładowywanie klas i interfejsów

Klasa lub interfejs mogą zostać wyładowane wtedy i tylko wtedy, gdy ich definiujący program ładujący klasy może zostać odzyskany przez moduł odśmiecania pamięci [...] Klasy i interfejsy załadowane przez moduł ładujący nie mogą zostać usunięte.

bruno conde
źródło
@bruno, Czy to oznacza, że ​​program ładujący klasy zawiera odniesienie do każdej ładowanej klasy, nawet jeśli ładowana klasa nie ma statycznych elementów członkowskich?
Pacerier,
@brunoconde, nie sądzę, że to prawda. Który dokładnie akapit to stwierdza? (Kontynuuj dyskusję na stackoverflow.com/questions/405364/ ... )
Pacerier,
Kiedy program ładujący klasy kwalifikowałby się do czyszczenia pamięci. ?
Rohit Bandil
@RohitBandil - gdy jest nieosiągalny.
Stephen C
55

Do zmiennych statycznych odwołują się obiekty Class, do których odwołują się ClassLoaders - więc chyba że ClassLoader w jakiś sposób upuści Class (jeśli jest to w ogóle możliwe) lub sam ClassLoader będzie kwalifikował się do zbierania (bardziej prawdopodobne - pomyśl o wyładowaniu aplikacji internetowych) zmiennych statycznych (lub raczej obiekty, do których się odnoszą), nie zostaną zebrane.

Jon Skeet
źródło
1
Czy do Classobiektów, które nie zawierają zmiennych statycznych, odwołuje się program ładujący klasy?
Pacerier
14

Jeśli chcesz, aby tymczasowy obiekt był używany do statycznej inicjalizacji, a następnie został usunięty, możesz użyć statycznego bloku inicjalizatora, np.

class MyUtils {
   static
   {
      MyObject myObject = new MyObject();
      doStuff(myObject, params);
   }

   static boolean doStuff(MyObject myObject, Params... params) {
       // do stuff with myObject and params...
   }
}

ponieważ statyczny blok inicjalizatora jest specjalnym rodzajem statycznej metody, myObject jest zmienną lokalną i może zostać usunięty po zakończeniu wykonywania bloku.

finnw
źródło
13

myObject jest odniesieniem, a nie obiektem . Obiekt jest automatycznie usuwany jako śmieci, gdy żadne odniesienie do niego nie wskazuje, ponieważ jest nieosiągalny.

Zatem także obiekt znajdujący się za statycznym odwołaniem „myObject” może zostać usunięty, jeśli wyłuskujemy go za pomocą

myObject = null;

i nie ma innych odniesień do tego obiektu.

Jednak statyczne odniesienia i zmienne pozostają przez cały okres istnienia programu.

Felix Keil
źródło
Witamy w StackOverflow! Ustawienie obiektu nullna koniec static blockjest realną opcją. Jednak w moim przypadku żywotność obiektu musiała być dłuższa niż statyczny blok. Koniec użyteczności obiektu nie był zbyt konkretny; dlatego pytam o wykorzystanie kolektora śmieci.
Michael Deardeuff,
7

Myślę, że to odpowiada na twoje pytanie - w zasadzie nie, chyba że klasa pochodzi ze specjalnego modułu ładującego klasy, który rozładowuje klasę.

Tomek
źródło
0

Kluczem jest tutaj Garbage Collection instancji klas, czyli obiektów. Instancja ClassLoader jest w istocie obiektem. Więc jeśli obiekt Classloader nie jest wyrzucany do śmieci, wszelkie odniesienia do nich przechowywane w stercie (tj. Statyczne rzeczy) prawie nigdy nie będą zbierane jako śmieci. Wyjątkiem jest pula ciągów.

Więc zanim nagle zdecydujesz się to zrobić private static MyGiantClass myGiantObject = new MyGiantClass() Pomyśl dwa razy, tak jak nauczyłem się na własnej skórze.

ha9u63ar
źródło