Настройка сборки мусора ничем не отличается от других действий по настройке производительности.
Вместо того, чтобы поддаться искушению настроить случайные части приложения, вам необходимо убедиться, что вы понимаете текущую ситуацию и желаемый результат. В общем, это так же просто, как следующий процесс:
- Укажите ваши цели производительности
- Запустить тесты
- Мера
- Сравните с целями
- Внести изменения и вернуться к выполнению тестов
Важно, чтобы цели могли быть установлены и измерены в трех измерениях, все они имеют отношение к настройке производительности. Эти цели включают в себя задержку, пропускную способность и емкость, понимание которых я могу рекомендовать, чтобы взглянуть на соответствующую главу в Руководстве по сборке мусора .
Давайте посмотрим, как мы можем начать исследовать, как постановка и достижение таких целей выглядит на практике. Для этого давайте рассмотрим пример кода:
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] |
Основываясь на информации в журнале, мы можем начать улучшать ситуацию с тремя разными целями.
- Убедиться, что пауза GC в худшем случае не превышает заданный порог
- Убедиться, что общее время, в течение которого потоки приложений останавливаются, не превышает заранее установленный порог
- Снижение затрат на инфраструктуру при одновременном обеспечении достижения разумных задержек и / или пропускной способности.
Для этого приведенный выше код был запущен в течение 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 . |