Обоснование для Soft- / Weak- / PhantomReferences очистки ссылок на объекты, которые ссылаются на отслеживаемый объект - PullRequest
0 голосов
/ 16 июня 2019

Документация для Soft -, Weak - и PhantomReference с включает в себя строку, аналогичную следующей (взято из PhantomReference):

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

То, что меня смущает, - это то, что касается других фантомно достижимых объектов.

Если я правильно понимаю, это описывает этот случай:
Объекты:

  • A
  • B

Ссылки:

  • ->: Сильная ссылка
  • -P->: ссылка на фантом
-> A
-P-> B -> A

По какой-то причине сборщик мусора еще не определил, что B только фантомно достижим. Теперь, если A становится фантомно достижимым, и сборщик мусора обнаруживает это, необходимо (согласно приведенному выше документу) также очистить ссылку на B.

Есть ли причина, по которой документация требует этого? Похоже, что если бы другие поставщики разработали JVM, это было бы довольно обременительно.

1 Ответ

1 голос
/ 20 июня 2019

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

Предположим, у вас есть следующая ситуация:

(weak)→ A
(weak)→ B (strong)→ A

технически, и A, и B слабо достижимы, но мы можем изменить это, вызывая метод get() для любой слабой ссылки, чтобы получить сильную ссылку на его референт.

Когда мы делаем это для первой слабой ссылки, чтобы получить сильную ссылку на A, объект B останется слабо достижимым, но когда мы сделаем это, чтобы получить сильную ссылку на B, объект A также станет сильно достижимым из-за сильной ссылки от B до A.

Таким образом, у нас есть правило, что, если слабая ссылка на A очищается,слабая ссылка на B должна быть очищена, так как в противном случае можно было бы получить сильную ссылку на A через B, несмотря на то, что слабая ссылка на A была очищена.И чтобы быть на безопасной стороне, это должно происходить атомарно, поэтому нет никакого возможного состояния гонки, позволяющего получить ссылку на B между разрешением двух ссылок.

Как уже говорилось, это имеет меньшее значениедля фантомных ссылок, поскольку они не позволяют получить ссылку, но нет никаких оснований рассматривать их по-разному.

Дело здесь в том, что это не реальное бремя, учитывая, как на самом деле работают сборщики мусора.Они должны пересекать все живые ссылки, то есть сильно достижимые объекты, и все, что не встречается, является мусором на удаление.Таким образом, при обнаружении слабой ссылки во время обхода она не будет проходить референт, но помнит объект ссылки.После завершения обхода он будет проходить через все встреченные ссылочные объекты и посмотреть, был ли референт помечен как достижимый по другому пути.Если нет, эталонный объект очищается и связывается для постановки в очередь.

Для решения вашего примера:

(strong)→ A
(weak)→ B (strong)→ A

Здесь B слабо достижимо независимо от строгой ссылки на A,Когда вы устраняете сильную ссылку на A, B все еще слабо достижим и может быть поставлен в очередь.Формально, A теперь слабо достижим, но JVM никогда не обнаружит это, не обнаружив, что B тоже слабо достижимо.Единственный способ обнаружить, что A является слабо достижимым, - это просмотреть контрольный граф, начиная с слабо достижимого B.Но никакая реализация не делает этого.Сборщик мусора просто очистит слабую ссылку на B и все.

...