Почему короткие и долгоживущие объекты влияют на сборку мусора? - PullRequest
22 голосов
/ 12 апреля 2010

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

  • Почему это так?
  • Это специфично для JVM Sun или это результат общего принципа сборки мусора?

Ответы [ 8 ]

22 голосов
/ 12 апреля 2010

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

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

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

Вы можете настроить параметр владения с помощью

java -XX:MaxTenuringThreshold=16 

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

java -XX:-PrintTenuringDistribution
10 голосов
/ 16 апреля 2010

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

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

4 голосов
/ 12 апреля 2010

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

Вот пример:

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 голосов
/ 12 апреля 2010

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

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

2 голосов
/ 12 апреля 2010

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

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

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

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

1 голос
/ 12 апреля 2010

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

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

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

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

1 голос
/ 12 апреля 2010

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

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

1 голос
/ 12 апреля 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...