Слабая ссылка Java не освобождается после System.gc () - PullRequest
0 голосов
/ 26 января 2019

У меня есть простой фрагмент:

Integer integer = 2;
WeakReference<Integer> wi = new WeakReference<>(integer);
WeakReference<Integer> sr = new WeakReference<>(new Integer(3));
System.out.println(wi.get());
System.out.println(sr.get());
System.gc();
System.out.println("step 1 wi = " + wi.get());
System.out.println("step 1 sr =: " + sr.get());
integer = null;
System.gc();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("step 1 wi = " + wi.get());
System.out.println("step 1 sr =: " + sr.get());

Вызов System.gc () должен заставить все слабые ссылки быть переработанными, верно, и я даже подождал 1 секунду, чтобы убедиться, что gc () происходит. Но даже когда установлено «integer = null», «wi» отказывается быть нулевым. Хотя sr имеет значение null сразу после "System.gc ()". Это печатает:

2
3
step 1 wi = 2
step 1 sr =: null
step 1 wi = 2
step 1 sr =: null

Мои вопросы: (1) Какова основная разница между Wi и SR? (2) как заставить jvm перерабатывать с wi?

Большое спасибо.

1 Ответ

0 голосов
/ 26 января 2019

Это не имеет ничего общего ни с тем, что System.gc() не дает никаких гарантий (это не так, но не потому, что вы видите то, что вы видите), ни с тем, как слабые ссылки взаимодействуют с gc.

Класс j.l.Integer содержит «кэш» экземпляров для Integer для всех значений байтов, поэтому от -128 до +127. Вы можете посмотреть это в действии:

System.out.println(Integer.valueOf(127) == Integer.valueOf(127));
System.out.println(Integer.valueOf(128) == Integer.valueOf(128));

Вышеуказанные отпечатки true false.

Этот код:

Integer x = 2;

- это синтаксис сахара. То, что компилятор на самом деле заканчивает компиляцией, потому что 'autoboxing' - это плод воображения javac (JVM ничего не знает об этом, это полностью делает javac для вас), это код:

Integer x = Integer.valueOf(2);

тогда как, конечно, если вы позвоните new Integer, вы ВСЕГДА получите новый объект, потому что, в общем-то, именно об этом говорится в спецификации. Вы также можете проверить это:

System.out.println(new Integer(5) == new Integer(5));

вышеперечисленные отпечатки false.

Фактически, сам класс java.lang.Integer содержит ссылку на то, на что указывает ваша ссылка wi, следовательно, он никогда не собирается.

Повторите тот же код, но на этот раз вместо '= 2', попробуйте '= 128', и на этот раз он соберет то же самое, что и sr.

...