#java #garbage-collection #scjp
#java #сбор мусора #scjp
Вопрос:
Мне задали вопрос (на этом сайте http://scjptest.com /): Сколько объектов подходит для сборки мусора в этом примере кода в строке // некоторый код идет здесь?
class A {
private B b;
public A() {
this.b = new B(this);
}
}
class B {
private A a;
public B(A a) {
this.a = a;
}
}
public class Test {
public static void main(String args[]) {
A aa = new A();
aa = null;
// some code goes here
}
}
Правильный ответ: «Объекты, на которые ссылаются a и b, имеют право на сборку мусора».. Но почему? они содержат ссылки цикла друг на друга, они доступны друг другу.
Спасибо!
Ответ №1:
они содержат ссылки цикла друг на друга, они доступны друг другу.
Да, но они больше не доступны из другого места, поэтому их больше нельзя увидеть и использовать в программе.
У ранних GCS были проблемы со сбором таких групп объектов, ссылающихся на себя, но с современными сборщиками поколений это решаемая проблема.
Вкратце, GC может просматривать сеть ссылок из известных статических объектов и объектов стека, и либо
- скопируйте все найденные объекты в новый пул памяти, автоматически оставляя после себя любые «мертвые» объекты (это стратегия «молодого поколения»), или
- отметьте все найденные объекты, чтобы после обхода всей сети ссылок можно было удалить все немаркированные объекты (это стратегия «старого / постоянного поколения»).
Ответ №2:
Это потому, что в Java есть сборщик мусора поколений, поэтому он может собирать группы объектов, которые имеют ссылки между ними, но не из основного приложения.
Здесь есть более подробное объяснение.
Насколько я помню (и я могу ошибаться), это было не так со старыми версиями java (такими как java 1.2), в которых циклические зависимости должны были быть очищены вручную, чтобы GC мог их собрать.
Комментарии:
1. Я не думаю, что проблема заключается в том, что gc является поколенческим; это просто деталь реализации для определенных JVM. Дело в том, что нет ссылок из корневого набора, поэтому объекты подходят для gc.
2. @Simon: в старых GCs только мусор собирал объект, только если счетчик ссылок был равен 0. Итак, если бы у вас было 2 объекта со ссылками друг на друга, они никогда не были бы GCed. К счастью, в наши дни это древняя история.
3. Обнаружение циклов не связано с типом используемого GC, единственным исключением является пересчет (отдельно; существует несколько популярных языковых реализаций, которые используют пересчет, но имеют простой GC для циклов), и можно поспорить, что он считается GC именно из-за этого ограничения. Итак, если ранняя Java не выполняла сборку мусора должным образом, ваша память неверна.
4. @Delnan Тогда я оставлю вам упражнение по просмотру документов java 1.1 / 1.2 🙂
5. Что ж, javacoffeebreak.com/articles/thinkinginjava / … является «авторским правом 1998, 1999, 2000» и говорит, что «Подсчет ссылок обычно используется для объяснения одного вида сборки мусора, но, похоже, он не используется ни в одной реализации JVM». Я посмотрю, смогу ли я найти что-нибудь еще, но я считаю это невозможным и был бы признателен за ссылку.
Ответ №3:
GC может удалить так называемый «остров объектов», если ни один из объектов с этого «острова» (или группы) не может быть доступен из любого потока!
В вашем примере вы создаете объект A, который имеет ссылку на другой объект B. Но объект B не является «ссылочным» для любого, кто ожидает A. Вы можете рассматривать два объекта как остров. Когда A исчезнет, GC будет достаточно умен, чтобы выяснить, что на B не может ссылаться ни один другой поток, и, таким образом, у вас будут удалены 2 объекта.
Комментарии:
1. 1 для этого определения: того, которое есть в книге SCJP6 от Sierra amp; Bates
Ответ №4:
давайте нарисуем сценарий, чтобы четко понять.
A a = new A()
a ———— это указывает на object————> A () «1-й объект»
в конструкторе A () вы создаете экземпляр экземпляра B () «2-го объекта»
внутри экземпляра класса B просто указывает на A () выше, поэтому новый объект не создан. В тот момент, когда вы присвоили переменной «a» значение null, никакая ссылка не будет указывать на объект (). Теперь у вас есть 2 объекта, подходящих для GC. Не беспокойтесь о том, что классы ссылаются друг на друга, просто сосредоточьтесь на объявлении внутри вашего основного метода.