Сборка мусора в Java выполняется на основе «достижимости». JLS определяет термин следующим образом:
"Достижимый объект - это любой объект, к которому можно получить доступ в любом потенциальном продолжающемся вычислении из любого живого потока."
Пока объект достижим *, он не подходит для сборки мусора.
JLS оставляет за собой реализацию Java, чтобы выяснить, как определить, доступен ли объект . Если реализация не может быть уверена, она может обрабатывать теоретически недоступный объект как достижимый ... и не собирать его. (Действительно, JLS позволяет реализации не собирать ничего, никогда! Хотя разумная реализация не сделала бы это.)
На практике (консервативная) достижимость рассчитывается путем отслеживания; посмотрим, чего можно достичь, следуя ссылкам, начинающимся с переменных класса (статических) и локальных переменных в стеках потоков.
Вот что это значит для вашего вопроса:
Если я позвоню: myTree = null;
что на самом деле происходит со связанными объектами TreeNode внутри дерева? Будет ли сбор мусора, или я должен установить все нулевые связанные объекты внутри объекта дерева ??
Предположим, что myTree
содержит последнюю оставшуюся доступную ссылку на корень дерева.
- Ничего не происходит немедленно.
- Если внутренние узлы ранее были доступны только через корневой узел, то они теперь недоступны и могут быть использованы для сбора мусора. (В этом случае присвоение
null
ссылкам на внутренние узлы не требуется.)
- Однако, если внутренние узлы были доступны через другие пути, они предположительно по-прежнему достижимы и, следовательно, НЕ подходят для сбора мусора. (В этом случае присвоение
null
ссылкам на внутренние узлы является ошибкой. Вы разбираете структуру данных, которую позже может попытаться использовать что-то другое.)
Если myTree
не содержит последнюю оставшуюся доступную доступную ссылку на корень дерева, то обнуление внутренней ссылки является ошибкой по той же причине, что и в 3. выше.
Так когда должны вам null
вещи, которые помогут сборщику мусора?
Случаи, когда вам нужно беспокоиться, это когда вы можете выяснить, что ссылка в некоторой ячейке (локальная, переменная экземпляра или класса, или элемент массива) больше не будет использоваться, но компилятор и среда выполнения не могут! Случаи делятся примерно на три категории:
- Ссылки на объекты в переменных класса ... которые (по определению) никогда не выходят за рамки.
Ссылки на объекты в локальных переменных, которые все еще находятся в области видимости ... но не будут использоваться. Например:
public List<Pig> pigSquadron(boolean pigsMightFly) {
List<Pig> airbornePigs = new ArrayList<Pig>();
while (...) {
Pig piggy = new Pig();
...
if (pigsMightFly) {
airbornePigs.add(piggy);
}
...
}
return airbornePigs.size() > 0 ? airbornePigs : null;
}
В приведенном выше примере мы знаем, что если pigsMightFly
равно false, объект списка не будет использоваться. Но никакой ожидаемый компилятор Java не может этого понять.
Ссылки на объекты в переменных экземпляра или в ячейках массива, где инварианты структуры данных означают, что они не будут использоваться. Примером стека @ edalorzo является пример этого.
Следует отметить, что компилятор / среда выполнения могут иногда выяснить, что переменная в области действия фактически мертва. Например:
public void method(...) {
Object o = ...
Object p = ...
while (...) {
// Do things to 'o' and 'p'
}
// No further references to 'o'
// Do lots more things to 'p'
}
Некоторые Java-компиляторы / среды выполнения могут быть в состоянии обнаружить, что 'o' не нужен после окончания цикла, и обрабатывать переменную как мертвую.
* На самом деле мы говорим о сильной достижимости. Модель достижимости GC более сложна, если учесть мягкие, слабые и фантомные ссылки. Однако они не относятся к сценарию использования OP.