Ситуацию МОЖНО воспроизвести: достаточно просто воспроизвести следующий код. И вопрос задан по существу и касается механизма работы сборщика мусора.
Если сборщик мусора запустится сразу после выполнения m1 = null; m2 = null;, то сколько объектов будет недоступны, и поэтому могут быть удалены сборщиком мусора?
public class MyTest {
MyTest m;
void show() {
System.out.println("Привет, Мир.");
}
public static void main(String args[]) {
MyTest m1 = new MyTest();
MyTest m2 = new MyTest();
MyTest m3 = new MyTest();
m1.m = m2;
m2.m = m3;
m3.m = m1;
m1 = null;
m2 = null;
// Вопрос: если сборщик мусора запустится здесь, то сколько объектов будет недоступны, и поэтому могут быть удалены сборщиком мусора?
}
}
Ответ
Вы удивитесь, но правильный ответ - Implementation defined
В том смысле, что в зависимости от реализации JVM могут быть освобождены хоть все объекты MyTest, хоть ни одного. И в обоих случаях поведение будет абсолютно корректным по отношению к Java Language Specification и Java Memory Model
Докажу на примере:
public static void main(String args[]) {
MyTest m1 = new MyTest();
MyTest m2 = new MyTest();
MyTest m3 = new MyTest();
m1.m = m2;
m2.m = m3;
m3.m = m1;
m1 = null;
m2 = null;
// Слабая ссылка обнулится, как только объект m3 будет собран
WeakReference ref = new WeakReference<>(m3);
for (int i = 0; ref.get() != null; i++) {
if ((i % 1000) == 0) System.gc();
}
System.out.println("m3 is garbage-collected");
}
После нескольких тысяч итераций цикла метод скомпилируется JITом, ссылок на объект m3 больше не будет, и он удалится после очередной сборки мусора. Однако если запустить Java с флагом -Xint, то ссылка на m3 всегда будет лежать доступной на стеке, и программа зациклится.
Забавно, но факт: даже объект this может быть освобождён сборщиком мусора прямо во время выполнения метода на этом объекте. Подробности в JDK-8055183
В Java 9 даже будут дополнения к Java Memory Model и специальный метод Reference.reachabilityFence, чтобы избежать подобных курьёзов.
Комментариев нет:
Отправить комментарий