Подтвердить что ты не робот

Циркулярные ссылки в Java

Учитывая агрегацию экземпляров класса, которые ссылаются друг на друга в сложной, круговой форме: возможно ли, что сборщик мусора не сможет освободить эти объекты?

Я смутно помню, что это было проблемой в JVM в прошлом, но я думал, что это было разрешено много лет назад. тем не менее, некоторое исследование в jhat показало, что круговая ссылка является причиной утечки памяти, с которой я столкнулся сейчас.

Примечание. У меня всегда создавалось впечатление, что JVM способна разрешать круговые ссылки и освобождать из памяти такие "острова мусора". Тем не менее, я задаю этот вопрос только для того, чтобы узнать, не нашли ли какие-либо исключения.

4b9b3361

Ответ 1

Только очень наивная реализация будет иметь проблемы с циркулярными ссылками. В Wikipedia есть хорошая статья по различным алгоритмам GC. Если вы действительно хотите узнать больше, попробуйте (Amazon) Сбор мусора: алгоритмы автоматического управления динамической памятью. У Java был хороший сборщик мусора с 1.2 и исключительно хороший в 1.5 и Java 6.

Тяжелая часть для улучшения GC - это сокращение пауз и накладных расходов, а не базовые вещи, такие как круговая ссылка.

Ответ 2

Сборщик мусора знает, где находятся корневые объекты: статика, locals в стеке и т.д., и если объекты недоступны из корня, они будут восстановлены. Если они достижимы, то им нужно придерживаться.

Ответ 3

Райан, судя по вашему комментарию к Циркулярные ссылки в Java, вы попали в ловушку ссылок объектов из класса, который, вероятно, был загружен бутстрапом/системой Загрузчик классов. Каждому классу ссылается загрузчик классов, который загружает класс, и поэтому может быть собран в мусор, только если загрузчик классов больше не доступен. Уловка заключается в том, что загрузчик bootstrap/system classloader никогда не собирает мусор, поэтому объекты, доступные из классов, загружаемых системным загрузчиком классов, не могут собираться с помощью мусора.

Обоснование этого поведения объясняется в JLS. Например, третье издание 12.7 http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7.

Ответ 4

Если я правильно помню, то в соответствии со спецификациями есть только гарантии того, что JVM не может собрать (что-то доступное), а не то, что он соберет.

Если вы работаете с JVM в реальном времени, большинство современных сборщиков мусора должны иметь возможность обрабатывать сложные справочные структуры и идентифицировать "подграфы", которые можно безопасно исключить. Эффективность, латентность и вероятность этого улучшаются с течением времени, поскольку все больше идей исследований проникают в стандартные (а не исследовательские) виртуальные машины.

Ответ 5

Нет, по крайней мере, используя Sun JVM, сборщик мусора сможет обнаружить эти циклы и освободить память, как только больше не будет ссылок снаружи.

Ответ 6

В спецификации Java говорится, что сборщик мусора может мусор собирать ваш объект ТОЛЬКО Если он недоступен из любого потока.

Достижимое означает, что существует ссылка или цепочка ссылок, которая ведет от А к В, и может пройти через C, D,... Z для всего, что он заботится.

JVM, не собирающий вещи, не был проблемой для меня с 2000 года, но ваш пробег может отличаться.

Совет. Сериализация Java кэширует объекты, чтобы сделать передачу сетки объектов эффективной. Если у вас много больших, переходных объектов, и вся ваша память становится забитой, reset ваш сериализатор очищает кеш.

Ответ 7

Просто чтобы усилить сказанное:

Приложение, с которым я работаю в течение шести лет, недавно изменилось с Java 1.4 на Java 1.6, и мы обнаружили, что нам пришлось добавлять статические ссылки на вещи, которые мы даже не понимали, были сборкой мусора до, Нам раньше не нужна статическая ссылка, потому что сборщик мусора использовался, чтобы сосать, и теперь это намного лучше.

Ответ 8

Ссылки на подсчет ссылок являются печально известными по этой проблеме. Примечательно, что SunS JVM не использует контрольный счетчик GC.

Если объект не может быть доставлен из корня кучи (как правило, как минимум, через загрузчики классов, если ничего больше 0, тогда объекты будут уничтожены, поскольку они не будут скопированы во время типичного Java GC в новую кучу.

Ответ 9

Циклическая ссылка происходит, когда один объект ссылается на другой, а другой ссылается на первый объект. Например:

class A {
private B b;

public void setB(B b) {
    this.b = b;
}
}

class B {
private A a;

public void setA(A a) {
    this.a = a;
}
}

public class Main {
public static void main(String[] args) {
    A one = new A();
    B two = new B();

    // Make the objects refer to each other (creates a circular reference)
    one.setB(two);
    two.setA(one);

    // Throw away the references from the main method; the two objects are
    // still referring to each other
    one = null;
    two = null;
}
}

Сборщик мусора Java достаточно умен, чтобы очищать объекты, если есть циклические ссылки, но нет живых потоков, которые имеют какие-либо ссылки на объекты больше. Таким образом, такая циклическая ссылка не создает утечки памяти.

Ответ 10

Сборщик мусора - очень сложная часть программного обеспечения - он был протестирован в огромном наборе тестов JCK. Это НЕ идеально, но есть очень хороший шанс, что до тех пор, пока java-компилятор (javac) скомпилирует все ваши классы, и JVM будет его создавать, тогда вы должны быть хорошими.

Затем, если вы держите ссылки на корень этого графа объектов, память НЕ будет освобождена, но если вы знаете, что делаете, вы должны быть в порядке.