Сборка мусора - почему c3 не подлежит сбору в этом примере (SCJP 6)

Взято из подготовительной книги SCJP 6 -

Дано:

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
    }
}

Когда достигается // doStuff, сколько объектов подходит для GC?

A. 0

B. 1

C. 2

D. Ошибка компиляции

Е. Невозможно узнать

F. Во время выполнения генерируется исключение

Правильный ответ: C — «Только один объект CardBoard (c1) подходит, но он имеет связанный с ним объект-оболочку Short, который также подходит».

Мой вопрос: почему c3 не подходит для сбора?

Мои мысли -

c1.go(c2) устанавливает локальную ссылочную переменную cb (которая является копией c2) в значение null, а затем возвращает cb, присвоенное c3. Я знаю, что ссылочная переменная для самого c2 не может быть изменена в методе, только объект, стоящий за ней. Однако мне кажется, что копия ссылочной переменной cb имеет значение null и присваивается c3. Почему в этом случае для c3 не задано возвращаемое значение null?


person LiamRyan    schedule 18.09.2013    source источник
comment
Хм. Я не уверен, что мне нравится говорить, что Короткая обертка также подходит. Насколько я понимаю, прямо сейчас на объект Short ссылается объект CardBoard. Ссылка не удаляется до тех пор, пока CardBoard не получит GCed, верно? Кто-нибудь может это прокомментировать? Как только CardBoard получит GCed, Short теперь будет допущен к участию, но в данный момент я не думаю, что это возможно.   -  person Cruncher    schedule 18.09.2013
comment
На короткий объект ссылается картонный объект, однако из-за того, что он недоступен для живого потока, поскольку ссылка, содержащая ссылку, является нулевой, она также подходит (изолированная ссылка)   -  person LiamRyan    schedule 18.09.2013


Ответы (2)


Нет объекта, связанного с c3. Его значение равно null, поэтому собирать нечего.

person Kayaman    schedule 18.09.2013
comment
Да, если сначала был создан экземпляр c3, то он был бы готов к сборке мусора. - person Cruncher; 18.09.2013
comment
За деревьями не видно леса, спасибо, Каяман. - person LiamRyan; 18.09.2013
comment
@ LinuxN00b Я думаю, что примеры SCJP обычно совершенно бесполезны. Никто в здравом уме не стал бы писать такой код, который они используют в своих примерах, и обычно вы не тратите время на размышления о том, когда объекты собираются методом gc. - person Kayaman; 18.09.2013
comment
Верно, но мне нужно пройти их, чтобы сдать экзамен :) еще раз спасибо - person LiamRyan; 18.09.2013
comment
Ну тогда ты не хочешь знать, что я думаю об экзаменах :) - person Kayaman; 18.09.2013

Этот «правильный» ответ SCJP является поддельным. Правильный ответ: либо 4, либо «невозможно знать».

Если код читать буквально ("// do Stuff" - это просто комментарий), то объект, ранее доступный из c2, является таким же мертвым и подходящим для GC, как и тот, на который ранее ссылался из c1, и поскольку оба объекта теперь недоступны объекты имеют объекты c1.story и c2.story, которые также умрут вместе с ними, всего 4 объекта имеют право на сбор.

Однако, если элемент «// do Stuff» является заполнителем для некоторого неизвестного кода, то этот код может использовать или не использовать c2, что означает, что объект, на который ссылается c2, может быть или не быть мертвым и пригодным для сбора, когда этот код код достигнут. Поэтому, если мы не знаем, что на самом деле означает «//делаем что-то», то подходят либо 2, либо 4, и невозможно сказать, какие из них.

person Gil Tene    schedule 21.09.2013
comment
На самом деле ссылка C2 никогда не бывает нулевой, копия ссылки C2, переданная в метод c1.go(Cardboard c), обнуляется. Вы можете воздействовать на объекты за переданными ссылочными переменными, но вы не можете изменить объект, на который указывает исходная ссылочная переменная, из метода, которому она передается. - person LiamRyan; 22.09.2013
comment
@ LinuxN00b Гил определенно не споткнулся о том, что Java - это трюк с передачей по значению; он сказал, что в момент комментария // do stuff последнее использование c2 уже было пропущено; поэтому объект, на который ссылается c2, недостижим по определению (нет возможных будущих вычислений, которые могли бы получить к нему доступ). - person Marko Topolnik; 23.09.2015