Почему делают короткие и долговечные объекты различием в сборке "мусора"?

Я часто читал, что в JVM солнца недолгие объекты ("относительно новые объекты") могут быть собраны "мусор" более эффективно, чем долговечные объекты ("относительно старые объекты")

  • Почему то, что так?
  • Это характерно для JVM Sun, или это следует из общего принципа сборки "мусора"?
22
задан Daniel Rikowski 12 April 2010 в 07:41
поделиться

8 ответов

Большинство приложений Java создают объекты Java, а затем довольно быстро их отбрасывают, например, вы создаете несколько объектов в методе, а затем, когда вы выходите из метода, все объекты умирают. Большинство приложений ведут себя именно так, и большинство людей склонны кодировать свои приложения именно таким образом. Куча Java условно разбита на 3 части: постоянная, старое (долгоживущее) поколение и молодое (короткоживущее) поколение. Молодое поколение далее разбивается на S1, S2 и eden. Это просто кучи.

Большинство объектов создается в молодом поколении. Идея здесь в том, что, поскольку смертность объектов высока, мы быстро создаем их, используем и затем выбрасываем. Скорость имеет значение. По мере создания объектов young gen заполняется, пока не произойдет малый GC. При малом GC все живые объекты копируются из eden, скажем, из S2 в S1. Затем "указатель" останавливается на eden и S2.

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

Вы можете настроить параметр tenuring с помощью

java -XX:MaxTenuringThreshold=16 

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

java -XX:-PrintTenuringDistribution
22
ответ дан 29 November 2019 в 04:29
поделиться

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

Следовательно, объекты создаются в небольшом пространстве (называемом «Эдем» или «молодой ген»). Через некоторое время все объекты, которые могут быть достигнуты, копируются (= дорого) из этого пространства, а затем пространство объявляется пустым (так что Java эффективно забывает обо всех недостижимых объектах, поэтому они не имеют стоимости, поскольку они не должны быть скопированы). Со временем долгоживущие объекты перемещаются в «старые» пространства, а старые пространства вычищаются реже, чтобы уменьшить накладные расходы сборщика мусора (например, каждые N запусков сборщик мусора будет запускать старое пространство вместо пространства eden).

Для сравнения: если вы размещаете объект в C / C ++, вам нужно вызвать free () плюс деструктор для каждого из них. Это одна из причин, почему сборщик мусора работает быстрее, чем традиционное ручное управление памятью.

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

1
ответ дан 29 November 2019 в 04:29
поделиться

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

Вот пример:

public String concatenate(int[] arr) { 
  StringBuilder sb = new StringBuilder();
  for(int i = 0; i < arr.length; ++i)
    sb.append(i > 0 ? "," : "").append(arr[i]);
  return sb.toString();
}

Объект sb станет мусором, как только метод вернется.

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

4
ответ дан 29 November 2019 в 04:29
поделиться

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

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

Очень распространенная эвристика, применимая ко многим программам и языкам программирования, заключается в том, что многие объекты очень недолговечны, и большинство обращений на запись происходит в молодые объекты (те, которые были созданы недавно). Можно написать код приложения, который работает не так, но эта эвристика будет "в основном верна" для "большинства приложений". Таким образом, имеет смысл хранить молодые объекты в эффективно управляемой области. Что и делает JVM GC, и именно поэтому эта эффективная область называется "молодым поколением".

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

2
ответ дан 29 November 2019 в 04:29
поделиться

Это поколенная сборка мусора. В наши дни она используется довольно широко. Подробнее см. здесь: (wiki).

По сути, GC предполагает, что новые объекты с большей вероятностью станут недоступными, чем старые.

4
ответ дан 29 November 2019 в 04:29
поделиться

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

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

1
ответ дан 29 November 2019 в 04:29
поделиться

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

В Hotspot JVM новые объекты выделяются в так называемой области Eden. Когда эта область заполняется, JVM очищает область Eden (что не занимает много времени, поскольку она не очень большая). Объекты, которые еще живы, перемещаются в область Survivor, а остальные отбрасываются, освобождая Eden для следующего поколения. Когда коллекция Eden становится недостаточной, сборщик мусора переходит к более старым поколениям (что требует больше работы).

1
ответ дан 29 November 2019 в 04:29
поделиться

(см. Объяснения выше для более общего GC .. это отвечает, ПОЧЕМУ новое для GC дешевле, чем Старый).

Причина, по которой eden можно очистить быстрее, проста: алгоритм пропорционален количеству объектов, которые переживут сборку мусора в пространстве eden, а не количеству живых объектов во всей куче. то есть: если у вас средний уровень смертности объектов в eden составляет 99% (то есть: 99% объектов не выживают при сборке мусора, что не является ненормальным), вам нужно только посмотреть и скопировать этот 1%. Для "старого" GC все живые объекты в полной куче должны быть помечены / очищены. Это значительно дороже.

10
ответ дан 29 November 2019 в 04:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: