Статьи

Что такое показатель распределения?

скорость выделения ресурсов gcФразы, такие как «неустойчивая скорость размещения» и «вам нужно поддерживать низкий уровень распределения», по-видимому, относятся только к словарю Java Champions. Сложный, страшный и окруженный волшебной аурой.

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

Что такое показатель распределения и почему я должен заботиться?

Скорость выделения измеряется количеством памяти, выделенной на единицу времени. Часто он выражается в МБ / с, но вы можете использовать PB / за световой год, если хотите. Так что это все, что есть — никакой магии, только объем памяти, который вы выделяете в своем Java-коде, измеренный за определенный период времени.

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

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

Итак, сосредоточившись на GC, мы можем начать с аналогии, которая также верна в реальном мире — если вы создаете много вещей, вы, как правило, сталкиваетесь с большим количеством очистки после этого. Зная, что JVM построена с механизмом сбора мусора, необходимо выяснить, как скорость распределения изменяет частоту или продолжительность пауз GC.

Измерение уровня распределения

Давайте начнем с измерения уровня распределения. Для этого включим ведение журнала 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] 

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

  • Через 291 мс после запуска JVM было создано 33 280 тыс. Объектов. Первое небольшое событие GC очистило молодое поколение, после чего в молодом поколении осталось 5 088 тыс. Объектов.
  • Через 446 мс после запуска, занятость Young gen выросла до 38368K, что вызвало следующий сборщик мусора, что  позволило сократить занятость Young Gen до 5120K .
  • Через 829 мс после запуска размер Young gen составлял 71 680 К, и GC снова уменьшил его до 5120 КБ .

Эти данные затем могут быть выражены в следующей таблице для расчета коэффициента распределения как дельты занятости Юнга:

EventTimeYoung beforeYoung afterРаспределено во времяРаспределение распределения 1-й GC 291мс 33 280 КБ 5 088 КБ 33 280 КБ 114 МБ / с 2-й GC 446 мс 38 368 КБ 5 120 КБ 33 280 КБ 215 МБ / с 3-й ГК 829 мс 71 680 КБ 5 120 КБ 66 530 КБ / 020MB 17 173 0BB 17 173 0BB 17 173 0BB 17 173 0BB 17 173 0BB 17 1733BB 17 173 / BB 17 173 0BB 17 173 0BB 17 173 0BB 17 1733BB 17 1733BB 17 1733BB 17 1733BB 17 1733BB 17 1733BB 17 1733B 174 163 161MB / сек

Наличие этой информации позволяет нам сказать, что этот конкретный фрагмент программного обеспечения имел скорость выделения 161 МБ / с в течение периода измерения.

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

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

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

И действительно, при запуске одного и того же примера с разными размерами Eden с использованием параметров -XX: NewSize -XX: MaxNewSize & -XX: SurvivorRatio мы можем видеть двукратную разницу в скоростях распределения

  • Выполнение приведенного выше примера с 100M Eden снижает скорость выделения до уровня ниже 100MB / sec
  • Увеличение размера Eden до 1 ГБ увеличивает скорость выделения до чуть ниже 200 МБ / с.

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

Теперь, прежде чем вы сделаете вывод, что «чем больше Eden, тем лучше», вы должны заметить, что скорость выделения может и, возможно, не напрямую связана с фактической пропускной способностью вашего приложения. Это техническое измерение, способствующее пропускной способности. Скорость распределения может и будет влиять на то, как часто ваши второстепенные паузы в GC останавливают потоки приложений, но чтобы увидеть общее влияние, вам необходимо учитывать также большие паузы в GC и измерять пропускную способность не в МБ / с, а в бизнес-операциях вашего приложения. обеспечивает.