SCJP макет вопроса: Сколько объектов подходит для сборки мусора?

#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. Не беспокойтесь о том, что классы ссылаются друг на друга, просто сосредоточьтесь на объявлении внутри вашего основного метода.