2012-07-19 14 views
6

To pytanie pochodzi z Kathy SierraSCJP 1.6. Ile obiektów kwalifikuje się do zbierania śmieci?Obiekty kwalifikujące się do zbierania śmieci

Według odpowiedzi Kathy Sierra jest to C. Oznacza to, że dwa obiekty kwalifikują się do zbierania śmieci. Przekazałem wyjaśnienie odpowiedzi. Ale dlaczego c3 nie kwalifikuje się do garbage collection (GC)?

class CardBoard { 
    Short story = 200; 
    CardBoard go(CardBoard cb) { 
    cb = null; 
    return cb; 
} 

public static void main(String[] args) { 
    CardBoard c1 = new CardBoard(); 
    CardBoard c2 = new CardBoard(); 
    CardBoard c3 = c1.go(c2); 
    c1 = null; 
    // Do stuff 
} } 

Kiedy // Do stuff zostanie osiągnięty, ile obiektów kwalifikują się do GC?

  • A: 0
  • B: 1
  • C. 2
  • D: Opracowanie nie
  • E: Nie można wiedzieć
  • F: jest wyjątek przy starcie

Odpowiedź:

  • C jest poprawne. Tylko jeden obiekt CardBoard (c1) jest odpowiedni, ale ma powiązany obiekt opakowujący Short, który również kwalifikuje się.
  • A, B, D, E i F są nieprawidłowe w związku z powyższym. (Cel 7,4)
+0

Ściśle mówiąc "c3" nie może kwalifikować się do GC, ponieważ * nie jest obiektem *. Jest to zmienna, która może wskazywać na obiekt. –

+0

Poprawną odpowiedzią jest [wszystkie] (http://stackoverflow.com/a/26645534/2711488) ... – Holger

Odpowiedz

6

Żaden obiekt nigdy nie istniał, na który wskazuje c3. Konstruktor był wywoływany tylko dwa razy, dwa obiekty, z których jeden wskazywany jest przez c1 i c2. c3 to tylko odniesienie, do którego nigdy nie przypisano nic oprócz wskaźnika pustego.

Numer referencyjny c3, który obecnie wskazuje wartość zerową, nie wykracza poza zakres i zostanie usunięty ze stosu, dopóki nie zostanie przekroczony nawias zamykający na końcu metody głównej.

Obiekt pierwotnie przypisany do c1 jest nieosiągalny, ponieważ odniesienie c1 została ustawiona na null, ale odniesienie c2 nie został zmieniony, więc obiekt przypisany do niego jest jeszcze osiągalny z tego zakresu poprzez odniesienie c2.

+0

To ciekawe, że istnieje wiele samouczków i ćwiczeń omawiających takie rzeczy i wszystkie z nich są błędne. Prawda jest taka, że ​​JVM w ogóle nie ma wiedzy na temat zakresu zmiennych lokalnych. W przeszłości często sugerowało to, że niektóre referencje nie zostały usunięte, mimo że nie mieszczą się w zakresie. Dzisiaj możesz być zaskoczony faktem, że obiekt jest zbierany, mimo że jest "w zasięgu", zobacz ["finalize() wywołane na silnie osiągalnym obiekcie w Javie 8"] (http://stackoverflow.com/q/26642153/2711488) ... – Holger

+0

1) pytanie dotyczy języka Java 6 2) bez wiedzy o tym, co "// robić rzeczy" może zawierać, nie można spekulować na temat wniosków optymalizacyjnych, jakie kompilator może wyciągnąć na temat przyszłego osiągalności c2. – Affe

+0

Reguły między językami Java 6 i Java 8 nie uległy zmianie. Nie można nawet wykluczyć, że takie rzeczy zdarzają się w rzeczywistej implementacji Java 6, po prostu nie zostało to dotąd omówione na SO. A jeśli założysz, że '// rób rzeczy' może zawierać akcje związane z osiągalnością, poprawną odpowiedzią byłoby, że pytanie jest niekompletne. To po prostu dowodzi jeszcze bardziej, jak bezcelowe są takie pytania ... – Holger

4

c3 jest null, więc oczywiście nie ma Obiekt nie kwalifikuje się do zbierania śmieci.

Należy pamiętać, że tylko dwa CardBoard obiekty są tworzone, dwa na tych liniach:

CardBoard c1 = new CardBoard(); 
CardBoard c2 = new CardBoard(); 

i po żonglerki odniesienia, tylko jeden z nich jest bez referencji.

-1

Jeśli zauważysz, że w kodzie zostały utworzone tylko dwa obiekty. c3 nigdy nie jest inicjowane do obiektu, jest referencją zerową. Dlatego tylko jeden "obiekt" kwalifikuje się do zbierania śmieci.

7

Złammy tę linię w dół po linii:

CardBoard c1 = new CardBoard(); 

Mamy teraz dwa obiekty, to CardBoardc1 wskazuje na i Shortc1.story. Nie jest dostępny dla GC jako c1 punktów na CardBoard i story zmienny CardBoard punktów na Short ...

CardBoard c2 = new CardBoard(); 

Podobnie jak wyżej, teraz mamy cztery przedmioty, z których żadna nie są dostępne dla GC.

CardBoard c3 = c1.go(c2); 

Wzywamy sposób przejść na kartonie wskazał przez c1, przekazując wartość c2 co jest odwołaniem do CardBoard Object. Usuwamy parametr, ale Java jest przekazywana według wartości, co oznacza, że ​​sama zmienna c2 pozostaje niezmieniona. Następnie zwracamy parametr nulled. c3 to null,i c2 są niezmienione. Nadal mamy 4 obiekty, z których żaden nie może być GC.

c1 = null; 

We null c1. Obiekt CardBoard, który uprzednio wskazywał teraz, nie wskazuje na niego, a może być GC. Ponieważ zmienna story wewnątrz tego obiektu CardBoard jest jedyną rzeczą wskazującą na Short, a ponieważ ten obiekt CardBoard kwalifikuje się do GC, to Short również kwalifikuje się do GC. Daje nam to 4 obiekty, z których 2 mogą być oznaczone GC. Obiekty kwalifikujące się do GC to te, które wcześniej były oznaczone przez c1 i c1.story.

1

Formalnie poprawna odpowiedź brzmi, że nie wiemy. A powodem nie wiemy, jest to linia:

Short story = 200; 

To kompiluje się następujący kod bajtowy:

CardBoard(); 
Code: 
    0: aload_0 
    1: invokespecial #1     // Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: sipush  200 
    8: invokestatic #2     // Method java/lang/Short.valueOf:(S)Ljava/lang/Short; 
    11: putfield  #3     // Field story:Ljava/lang/Short; 
    14: return 

Linia 8 jest kluczem tutaj, Short.valueOf(), która zwraca pudełkowej odpowiednik pierwotny 200. Spójrzmy na Javadoc z Short.valueOf():

Ta metoda zawsze wartości cache w zakresie -128 do 127, włącznie, a może buforować inne wartości poza tym zakresem.

200 jest poza zakresem "wymuszania pamięci podręcznej", a zatem znajduje się w "pamięci podręcznej". Jeśli jest buforowany, wartość story nie będzie kwalifikować się do GC, jeśli zawiera instancję zawierającą CardBoard. Jeśli nie jest buforowany, story będzie nieosiągalny, a zatem GCed.

Aby kwestia jednoznaczna (a proponowana odpowiedź prawidłowa), kod powinien zostać zmieniony tak:

Short story = new Short(200); 

Aktualizacja:1.6 Javadoc dla Short.valueOf() jest raczej bardziej tajemnicze niż 1.8 wersji zacytowałem , ale ta sama logika ma zastosowanie: nie ma sposobu, aby stwierdzić, po prostu patrząc na kod, czy nowa lub buforowana instancja o numerze Short zostanie zwrócona.

Powiązane problemy