Статьи

Что такое ставка продвижения?

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

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

Это продолжение нашего поста с прошлой недели, которое объяснило концепцию  ставки распределения .

Скорость продвижения измеряется количеством данных, передаваемых от молодого поколения к старому поколению за единицу времени . Часто измеряется в МБ / с, аналогично скорости выделения. Как и в нашем посте о ставке распределения, давайте еще раз покопаемся, чтобы узнать, как рассчитывается ставка повышения и почему вы должны заботиться о ставке вообще.

Измерение скорости продвижения

Давайте начнем с измерения скорости продвижения. Для этого включим ведение журнала GC, указав -XX: + PrintGCDetails -XX: + PrintGCTimeStamps flags для JVM. JVM теперь начинает регистрировать паузы GC, как показано в следующем фрагменте:

0.291: [GC (Allocation Failure) [PSYoungGen: 33280K->5088K(38400K)] 33280K->24360K(125952K), 0.0365286 secs] [Times: user=0.11 sys=0.02, real=0.04 secs] 
0.446: [GC (Allocation Failure) [PSYoungGen: 38368K->5120K(71680K)] 57640K->46240K(159232K), 0.0456796 secs] [Times: user=0.15 sys=0.02, real=0.04 secs] 
0.829: [GC (Allocation Failure) [PSYoungGen: 71680K->5120K(71680K)] 112800K->81912K(159232K), 0.0861795 secs] [Times: user=0.23 sys=0.03, real=0.09 secs]

Из вышесказанного мы можем извлечь размер Young Generation и общую кучу как до, так и после события сбора. Зная потребление молодого поколения и общую кучу, легко вычислить потребление старого поколения как просто дельту между ними. Выражая информацию в журналах GC как:

Мероприятие Время Молодые уменьшились Всего уменьшилось Повышен Скорость продвижения
1-й ГК 291ms 28,192K 8,920K 19,272K 66,2 МБ / с
2-й ГК 446ms 33,248K 11,400K 21,848K 140,95 МБ / с
3-й ГК 829ms 66,560K 30,888K 35,672K 93,14 МБ / с
Общее 829ms 76,792K 92,63 МБ / с

позволит нам извлечь скорость продвижения за измеряемый период. Мы видим, что в среднем скорость продвижения составляла 92 МБ / с, а какое-то время она достигала 140,95 МБ / с.

Анализировать влияние

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

Опять же, аналогично скорости распределения, основное влияние уровня продвижения является изменение частоты пауз в GC. Но в отличие от уровня распределения, который влияет на частоту  незначительных  событий GC , уровень продвижения влияет на частоту  основных  событий GC . Позвольте мне объяснить — чем больше вы продвигаете старое поколение, тем быстрее вы его заполняете. Более быстрое заполнение Old gen означает, что частота очистки событий GC увеличится.

Копирование коллектора в живых космических ява

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

  • Большинство объектов быстро не используются
  • Те, которые обычно не выживают в течение (очень) долгого времени

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

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

Симптом, который сигнализирует о том, что приложение страдает от преждевременного продвижения, — это когда  уровень продвижения приближается к уровню распределения  . В нашем случае мы, безусловно, сталкиваемся с такой проблемой, поскольку наша скорость выделения составляет 161 МБ / с, а скорость продвижения составляет 92 МБ / с. Решение проблемы может быть таким же простым, как увеличение размера молодого поколения путем изменения  параметров -XX: NewSize ,   -XX: MaxNewSize  и  -XX: SurvivorRatio  .

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

Вынос

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