Гарантирует ли GC, что очищенные ссылки добавляются в ReferenceQueue в топологическом порядке? - PullRequest
4 голосов
/ 23 марта 2010

Скажем, есть два объекта, A и B, и есть указатель A.x --> B, и мы создаем, скажем, WeakReference s для A и B, со связанным ReferenceQueue.

Предположим, что и A, и B становятся недоступными.Интуитивно B нельзя считать недоступным до A.В таком случае, получаем ли мы каким-то образом гарантию, что соответствующие ссылки будут помещены в очередь в интуитивном (топологическом, когда нет циклов) порядке в ReferenceQueue?Т.е. ref (A) перед ref (B).Я не знаю, что если GC пометит группу объектов как недоступных, а затем поставит их в очередь в определенном порядке?

Я просматривал Finalizer.java гуавы, увидев этот фрагмент:

private void cleanUp(Reference<?> reference) throws ShutDown {
  ...
  if (reference == frqReference) {
    /*
     * The client no longer has a reference to the
     * FinalizableReferenceQueue. We can stop.
     */
    throw new ShutDown();
  }

frqReference - это PhantomReference на используемый ReferenceQueue, так что если этоGC'ed, нет Finalizable {Weak, Soft, Phantom} Ссылки могут быть живы, так как они ссылаются на очередь.Таким образом, они должны быть GC'ed, прежде чем сама очередь может быть GC'ed - но тем не менее, мы получаем гарантию, что эти ссылки будут помещены в ReferenceQueue в том порядке, в котором они «собраны» (как будто ониполучить GC'ed один за другим)?Код подразумевает, что существует какая-то гарантия, иначе необработанные ссылки теоретически могут остаться в очереди.

Спасибо

Ответы [ 3 ]

4 голосов
/ 23 марта 2010

Я почти уверен, что ответ - нет.

В спецификации JVM говорится о методах финализатора:

Виртуальная машина Java не накладывает упорядочения на вызовы метода finalize. Финализаторы могут быть вызваны в любом порядке или даже одновременно. ( JVM spec 2.17.7 )

Из этого я заключаю, что нет никаких гарантий, что ссылки поставлены в очередь в топологическом порядке.

3 голосов
/ 23 марта 2010

Гарантия заказа отсутствует.В случае Finalizer.java поток может быть остановлен до обработки всех ссылок.См. Документы для FinalizableReferenceQueue:

  • Сохраняйте строгую ссылку на этот объект, пока все связанные

  • ссылки не будут завершены.Если этот объект является мусором, собранным ранее,
  • вспомогательный поток не будет вызывать {@code finalizeReferent ()} для
  • оставшихся ссылок.

Это сделано намеренноповедение.Например, мы используем FRQ для очистки записей карты, когда очищены ссылки на ключи и / или значения.Если у пользователя больше нет ссылки на карту и, в свою очередь, больше нет ссылки на FRQ, нет смысла обрабатывать эти ссылки.

1 голос
/ 23 марта 2010

Я думаю, что нет такой гарантии.Сам GC не имеет полного и непосредственного представления об ОЗУ (оно не может, поскольку GC работает на ЦП, который может просматривать только несколько байтов за раз).В вашем примере, предполагая базовый GC «mark & ​​sweep», есть вероятность, что A и B будут объявлены недоступными на одной и той же фазе mark и сгруппированы в произвольном порядке.Поддержание топологического порядка, вероятно, будет дорогостоящим.

Что касается Finalizer, то кажется, что он предназначен для использования только через экземпляр FinalizableReferenceQueue, который совершает магию, связанную с загрузкой классов.Finalizer использует свои собственные средства для обнаружения того, когда FinalizableReferenceQueue, от которого он функционально зависит, становится недостижимым;это тот момент, когда поток, выполняющий Finalizer, знает, что он должен выйти.Из того, что я понимаю, если приложение позволяет GC вернуть FRQ, то поток финализатора завершится, и любые ссылки, помещенные в очередь «после» ссылки FRQ, не будут обработаны.Это зависит от топологического порядка или его отсутствия, но я не могу решить, является ли это проблемой или нет.Я думаю, что приложение не должно отбрасывать свой FRQ, пока важна обработка исправленных ссылочных объектов.

...