Статьи

GC тюнинг на практике

Мусоровоз Изолированный Настройка сборки мусора ничем не отличается от других действий по настройке производительности.

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

  1. Укажите ваши цели производительности
  2. Запустить тесты
  3. Мера
  4. Сравните с целями
  5. Внести изменения и вернуться к выполнению тестов

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

Давайте посмотрим, как мы можем начать исследовать, как постановка и достижение таких целей выглядит на практике. Для этого давайте рассмотрим пример кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//imports skipped for brevity
public class Producer implements Runnable {
 
  private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
 
  private Deque<byte[]> deque;
  private int objectSize;
  private int queueSize;
 
  public Producer(int objectSize, int ttl) {
    this.deque = new ArrayDeque<byte[]>();
    this.objectSize = objectSize;
    this.queueSize = ttl * 1000;
  }
 
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      deque.add(new byte[objectSize]);
      if (deque.size() > queueSize) {
        deque.poll();
      }
    }
  }
 
  public static void main(String[] args) throws InterruptedException {
    executorService.scheduleAtFixedRate(new Producer(200 * 1024 * 1024 / 1000, 5), 0, 100, TimeUnit.MILLISECONDS);
    executorService.scheduleAtFixedRate(new Producer(50 * 1024 * 1024 / 1000, 120), 0, 100, TimeUnit.MILLISECONDS);
    TimeUnit.MINUTES.sleep(10);
    executorService.shutdownNow();
  }
}

Код передает две работы для запуска каждые 100 мс. Каждое задание эмулирует объекты с определенным сроком службы: оно создает объекты, позволяет им уходить на заранее определенный промежуток времени, а затем забывает о них, позволяя GC освободить память.

При запуске примера с включенным ведением журнала GC со следующими параметрами

1
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps

мы сразу же увидим влияние GC в файлах журналов, как показано ниже:

1
2
3
2015-06-04T13:34:16.119-0200: 1.723: [GC (Allocation Failure) [PSYoungGen: 114016K->73191K(234496K)] 421540K->421269K(745984K), 0.0858176 secs] [Times: user=0.04 sys=0.06, real=0.09 secs]
2015-06-04T13:34:16.738-0200: 2.342: [GC (Allocation Failure) [PSYoungGen: 234462K->93677K(254976K)] 582540K->593275K(766464K), 0.2357086 secs] [Times: user=0.11 sys=0.14, real=0.24 secs]
2015-06-04T13:34:16.974-0200: 2.578: [Full GC (Ergonomics) [PSYoungGen: 93677K->70109K(254976K)] [ParOldGen: 499597K->511230K(761856K)] 593275K->581339K(1016832K), [Metaspace: 2936K->2936K(1056768K)], 0.0713174 secs] [Times: user=0.21 sys=0.02, real=0.07 secs]

Основываясь на информации в журнале, мы можем начать улучшать ситуацию с тремя разными целями.

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

Для этого приведенный выше код был запущен в течение 10 минут в трех разных конфигурациях, в результате чего были получены три совершенно разных результата, обобщенных в следующей таблице:

отвал GC Алгоритм Полезная работа Самая длинная пауза
-Xmx12g -XX: + UseConcMarkSweepGC 89,8% 560 мс
-Xmx12g -XX: + UseParallelGC 91,5% 1 104 мс
-Xmx8g -XX: + UseConcMarkSweepGC 66,3% 1610 мс

В эксперименте использовался один и тот же код с разными алгоритмами GC и разным размером кучи, чтобы измерить продолжительность пауз сборки мусора с учетом задержки и пропускной способности. Детали экспериментов и интерпретация результатов представлены в нашем Справочнике по сборке мусора . Посмотрите в справочнике примеры того, как простые изменения в конфигурации приводят к тому, что пример ведет себя совершенно по-разному в отношении задержки и пропускной способности.

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

Ссылка: GC-тюнинг на практике от нашего партнера JCG Никиты Сальникова Тарновского в блоге Plumbr Blog .