Молодое поколение все еще получает преимущество в скорости, если finalize () гарантированно будет вызываться при сборе? - PullRequest
2 голосов
/ 07 ноября 2019

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

Но у меня возник вопрос, в Java есть метод finalize() (хотя в JAVA 9 он устарел), еслиКоллектор гарантирует, что будет вызван finalize(), он должен сканировать недоступные объекты, а не просто идти сквозь живые объекты, и преимущество в скорости, похоже, исчезло.

Итак,

  1. Iя прав? (finalize() делает коллекции молодого поколения намного медленнее, а преимущество в скорости исчезает.)
  2. Если нет, то как JVM справилась с этой проблемой? (Например, игнорировать finalize()?)
  3. Помимо вышеуказанной проблемы, есть ли у молодого поколения и другие преимущества?

Редактировать: Я пишуgc для языка с функцией finalize(), я просто не могу быстро собрать коллекцию в этой ситуации.

1 Ответ

2 голосов
/ 07 ноября 2019

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

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

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

Для эффективности реализация может отслеживать классы, которые не переопределяют метод finalize класса Object, или переопределяет еготривиальным образом.

Например:

protected void finalize() throws Throwable {
    super.finalize();
}

Мы рекомендуем реализациям рассматривать такие объекты как имеющие финализатор, который не переопределяетсяи завершить их более эффективно, как описано в §12.6.1.

В случае JVM HotSpot он распознает, когда метод, унаследованный Object, не был переопределен иликогда он был переопределен пустым методом. Afaik, единственный супер-вызов не всегда распознается, но для вашего собственного языка, возможно, будет возможно его распознать.

Так что для большинства объектов в Java, finalize() не нужно вызывать, так как это никак не влияет и никогда не вызывается. Это решает проблему расширенного срока службы, поскольку теперь оно применяется только к нескольким объектам.

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

...