Java "мертвые" объекты не собирают мусор - PullRequest
2 голосов
/ 18 марта 2011

Я знаю, что во время сборки мусора в Java объекты, у которых больше нет ссылок на них, помечаются как «мертвые», так что они могут быть удалены из памяти сборщиком мусора.

Мой вопрос: если на этапе сбора мусора все «мертвые» объекты удаляются из памяти или некоторые из них выживают? Почему «мертвый» объект пережил фазу сбора мусора?

ПОСЛЕДНЕЕ РЕДАКТИРОВАНИЕ

Спасибо за все ваши ответы. Я могу сделать вывод, что основная причина, по которой «мертвые» объекты не будут удалены, связана с ограничениями по времени или интервалам работы сборщика мусора. Тем не менее, предполагая, что сборщик мусора может достичь всех «мертвых» объектов, мне было интересно, есть ли способ объявить, ссылаться, использовать, разыменовать и т. Д. Объект таким образом, чтобы каким-то образом пропустить этап удаления, даже если это "мертвый". Я думал, что, возможно, объекты, принадлежащие к классам, которые имеют статические методы или внутренние классы, или что-то подобное, по какой-то причине могут быть сохранены в памяти, даже если у них нет ссылок на них.
Возможен ли такой сценарий?

Спасибо

Ответы [ 6 ]

9 голосов
/ 18 марта 2011

Мой вопрос: если на этапе сбора мусора все «мертвые» объекты удаляются из памяти или некоторые из них выживают?Почему «мертвый» объект пережил фазу сбора мусора?

Все текущие ГХ HotSpot являются сборщиками поколений.Цитата из Википедии:

"Эмпирически отмечалось, что во многих программах наиболее недавно созданные объекты также являются объектами, которые чаще всего быстро становятся недоступными (известными как младенческая смертность или гипотеза поколений).Поколение GC (также известное как эфемерный GC) делит объекты на поколения и в большинстве циклов помещает только объекты подмножества поколений в исходный белый (осужденный) набор. Кроме того, система времени выполнения сохраняет информацию о том, когдассылки пересекают поколения, наблюдая за созданием и перезаписью ссылок. Когда сборщик мусора работает, он может использовать эти знания, чтобы доказать, что некоторые объекты в исходном белом наборе недоступны без необходимости обхода всего ссылочного дерева.Согласно гипотезе, это приводит к гораздо более быстрым циклам сбора данных, в то же время возвращая большинство недоступных объектов. "

Что это означает для вашего вопроса, так это то, что большинство GCциклы собирают только мусорные объекты в молодых поколениях.Объект мусора в самом старшем поколении может пережить многократные циклы GC ... пока наконец не будет собрано старое поколение.(И в новом G1 GC, по-видимому, старое поколение собирается немного за раз ... что может еще больше задержать рекультивацию.)

Другие причины (условно) недоступных объектов для выживания включают:

  • Недоступные объекты с (неисполненными) финализаторами присоединяются сборщиком мусора к очереди финализации для обработки после завершения GC.

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

  • Объекты, которые достижимы благодаря глобальным ссылкам JNI, и так далее,(спасибо @bestss)

  • Существуют различные скрытые ссылки, которые связывают экземпляры, их классы и их загрузчики классов.

  • Существует скрытая ссылка отвнутренний экземпляр к своему внешнему экземпляру.

  • Существует скрытая ссылка от класса на объекты intern'd String, которые представляют его строковые литералы.

Однако это все следствия определения достижимости:

«Достижимый объект - это любой объект, к которому можно получить доступ в любом потенциальном продолжающемся вычислении из любого живого потока." - JLS 12.6.1

Стоит также отметить, что правила для GC имеют элемент консервативности в отношении них.Они говорят, что достижимый объект не будет удален, но они не говорят, что объект (строго) недоступный будет удален.Это учитывает случаи, когда к объекту невозможно получить доступ, но система времени выполнения не может это выяснить.


Ваш дополнительный вопрос:

Однако, предположим, что сборщик мусораЯ могу узнать, есть ли способ объявить, ссылаться, использовать, разыменовать и т. д. объект, который каким-то образом пропустит этап удаления, даже если он «мертв».

«Мертвый» не является четко определенным термином.Если сборщик мусора может добраться до объектов, они по определению достижимы.Они не будут удалены, пока они еще достижимы.

Если они оба мертвы и достижимы (что бы ни означало «мертвые»!), То тот факт, что они достижимы, означает, что они не будут удалены.

То, что вы предлагаете, не имеет смысла.

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

Статические методы не имеют ссылок ... если только они не находятся в стеке вызовов.Тогда локальные переменные могут содержать ссылки, как и любой другой вызов метода.Применяются нормальные правила достижимости.

Статические поля являются корнями GC, пока существует сам класс.Применяются нормальные правила достижимости.

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

В итоге, есть некоторые неожиданные "причины" достижения, но все они являются логическим следствиемопределение достижимости.

3 голосов
/ 18 марта 2011

Одним из возможных объяснений недоступности недоступного объекта является время.Начиная с Java 1.5, время, которое JVM тратит на сбор мусора, может быть ограничено с помощью следующих параметров ...

  • -XX:MaxGCPauseMillis
  • -XX:GCTimeRatio=<nnn>

Оба варианта подробно объяснены здесь

3 голосов
/ 18 марта 2011

Как говорит System.gc () javadoc

Когда управление возвращается из вызова метода, виртуальная машина Java сделала все возможное, чтобы освободить пространство из всех отброшенныхobjects.

Из чего можно сделать вывод, что вызов сборщика мусора не гарантирует, что все неиспользуемые объекты будут возвращены.Поскольку сборка мусора может полностью отличаться в зависимости от реализации, однозначного ответа дать нельзя.Есть даже реализации java без какой-либо сборки мусора .

2 голосов
/ 18 марта 2011
  • В "молодом" поколении есть мертвые объекты, а в "старом" - мертвые. Если GC проводится в «несовершеннолетнем GC», будут собираться только мертвые объекты молодого поколения.
  • Кроме того, вы можете использовать метод finalize(), чтобы остановить VM от сбора вашего объекта, выдав исключение из finalize() (по крайней мере, так я понимаю Object.finalize() javadoc: Любое исключение, выданное finalize метод вызывает остановку завершения этого объекта, но в противном случае игнорируется ).
0 голосов
/ 18 марта 2011

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

0 голосов
/ 18 марта 2011

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

...