ОПТИМИЗАЦИЯ
ПОТРЕБЛЕНИЯ ПАМЯТИ В JAVA
делаем уборку правильно
12 ноября 2016
Евгений Берлог
EPAM Systems
Senior Software Engineer
2
3
4
ОСОБЕННОСТИ ЗАДАЧИ
# REST + MongoDB
# Жесткие требования к времени ответа
# Stateless
5
УСЛОВИЯ ТЕСТИРОВАНИЯ
# 10000 URL с реального окружения
# ~30 вызовов в секунду (реальная нагрузка + 50%)
ЗАМЕРЫ УСПЕШНОСТИ
# Максимальная пауза
# Пропускная способность
# Частота Full GC
7
Исходные замеры
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
1918мс 99.0% 5развчас
НЕМНОГО ТЕОРИИ
9
Распределение памяти
10
Первая сборка
11
Вторая сборка
12
Как происходит старение
13
Большая сборка
ГИПОТЕЗА
О СТАРЕНИИ ОБЪЕКТОВ
ГИПОТЕЗА О СТАРЕНИИ
ОБЪЕКТОВ
Время жизни
Размеробъектов
16
НО РЕАЛЬНАЯ И
ТЕОРЕТИЧЕСКАЯ
СИТУАЦИИ РАЗЛИЧАЮТСЯ
17
НО РЕАЛЬНАЯ И
ТЕОРЕТИЧЕСКАЯ
СИТУАЦИИ РАЗЛИЧАЮТСЯ
КАК
МОНИТОРИТЬ
СИТУАЦИЮ ?
19
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintTenuringDistribution
20
Вывод детализированного сообщения после каждого
запуска Garbage Collector’а.
-XX:+PrintGCDetails
dsc2016
[PSYoungGen: 1559493K->93696K(1610752K)] 2771413K->1379948K(5106176K),
0.1586049 secs]
21
-XX:+PrintGCTimeStamps
dsc2016
1914.990: [GC
[PSYoungGen: 1559493K->93696K(1610752K)] 2771413K->1379948K(5106176K),
0.1586049 secs]
Добавление в каждую GC-запись времени
относительно старта JVM.
22
-XX:+PrintTenuringDistribution
dsc2016
Desired survivor size 134217728 bytes, new threshold 15 (max 15)
Вывод в лог порога старения объектов и
необходимого размера Survivor региона.
23
1914.990: [GC
Desired survivor size 134217728 bytes, new threshold 1 (max 15)
[PSYoungGen: 1559493K->93696K(1610752K)] 2771413K->1379948K(5106176K),
0.1586049 secs]
1932.209: [GC
Desired survivor size 136839168 bytes, new threshold 1 (max 15)
[PSYoungGen: 1569792K->53234K(1611776K)] 2856044K->1408182K(5107200K),
0.1083012 secs]
dsc2016
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintTenuringDistribution
ADAPTIVE SIZE POLICY
26
ADAPTIVE SIZE POLICY – это попытка
JVM реорганизовать память с целью достичь
(#1) уменьшения GC паузы;
(#2) увеличения пропускной способности;
(#3) уменьшения footprint’а.
-XX:AdaptiveSizePolicyOutputInterval=1
27
ЛОГИ GC С ВКЛЮЧЕННЫМ ASP
UseAdaptiveSizePolicy actions to meet *** reduced footprint ***
GC overhead (%)
Young generation: 1.26 (attempted to shrink)
Tenured generation: 0.00 (no change)
Tenuring threshold: (attempted to decrease to balance GC costs) = 2
dsc2016
28
ЛОГИ GC С ВКЛЮЧЕННЫМ ASP
UseAdaptiveSizePolicy actions to meet *** reduced footprint ***
GC overhead (%)
Young generation: 1.26 (attempted to shrink)
Tenured generation: 0.00 (no change)
Tenuring threshold: (attempted to decrease to balance GC costs) = 2
dsc2016
30
Эксперимент #1:
Указываем максимальную задержку
-XX:GCTimeRatio=999
// по умолчанию 99
-XX:MaxGCPauseMillis=100
// по умолчанию не ограничен
32
Результат для максимальной
задержки
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
2092мс 99.0% 5развчас
# Выключаем Adaptive Size Policy
# Уменьшаем Old Generation
# Максимум на Eden
# Экспериментально высчитываем Survivor Size
35
Эксперимент #2:
Дальше не по правилам
36
Эксперимент #2:
Дальше не по правилам
-XX:-UseAdaptiveSizePolicy
-Xmx5G -Xms5G
-Xmn4300M
-XSurvivorRatio=6
38
Результат c выключенным
Adaptive Size Policy
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
1683мс 99.3% 1разв3.5часов
39
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
Базовыенастройки 1918МС 99.0% 5развчас
Максимальнаяпауза 2092МС 99.0% 5развчас
ВыключенныйASP 1683МС 99.3% 1разв3.5часов
Промежуточный результат
- Может пора остановиться?
Concurrent Mark Sweep
Collector
42
Concurrent Mark Sweep (CMS) Collector
# То же распределение регионов, что и в Parallel
# Тот же алгоритм, что и в Parallel для младшего
поколения
# Часть работы в старшем поколении
выполняется параллельно
# Больше footprint, чем в Parallel
44
Эксперимент #3:
Меняем GC!
-XX:+UseConcMarkSweepGC
-Xmx5G -Xms5G -Xmn4300M
-XX:SurvivorRatio=2
46
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
283мс 99.2% 1разв4часа
Результат c новым GC
47
dsc2016
: 1460888K->10522K(1595776K), 0.0049030 secs] 1697910K->247592K(2210176K),
0.0049871 secs]
1195.459: [GC1195.459: [ParNew
Desired survivor size 74252288 bytes, new threshold 15 (max 15)
- age 1: 690016 bytes, 690016 total
- age 2: 148448 bytes, 838464 total
- age 3: 751056 bytes, 1589520 total
...
- age 13: 82512 bytes, 3801784 total
- age 14: 607816 bytes, 4409600 total
- age 15: 1348728 bytes, 5758328 total
Анализ логов CMS
...
- age 13: 82512 bytes, 3801784 total
- age 14: 607816 bytes, 4409600 total
- age 15: 1348728 bytes, 5758328 total
15299.307: [GC [1 CMS-initial-mark: 581268K(839680K)] 1241313K(4142080K),
0.2830091 secs]
15306.520: [GC[YG occupancy: 1031447 K (3302400 K)]15306.520: [Rescan
(parallel) , 0.2487740 secs]15306.769: [weak refs processing, 0.0012183
secs]15306.770: [scrub string table, 0.0012292 secs] [1 CMS-remark:
581268K(839680K)] 1612715K(4142080K), 0.2518813 secs]
...
- age 13: 82512 bytes, 3801784 total
- age 14: 607816 bytes, 4409600 total
- age 15: 1348728 bytes, 5758328 total
15299.307: [GC [1 CMS-initial-mark: 581268K(839680K)] 1241313K(4142080K),
0.2830091 secs]
15306.520: [GC[YG occupancy: 1031447 K (3302400 K)]15306.520: [Rescan
(parallel) , 0.2487740 secs]15306.769: [weak refs processing, 0.0012183
secs]15306.770: [scrub string table, 0.0012292 secs] [1 CMS-remark:
581268K(839680K)] 1612715K(4142080K), 0.2518813 secs]
50
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
cms 283МС 99.2% 1разв4часа
parallel 1681МС 99.3% 1разв3.5часов
CMS vs PARALLEL
51
Почему не G1?
> G1 рекомендуется использовать при
размерах heap’а от 6ГБ
53
Эксперимент #4:
Используем сборщик G1
-XX:UseG1GC
55
Максимальнаяпауза Пропускнаяспособность ЧастотаFullGC
351мс 95.9% ?
Результат c использованием G1
57
Максимальнаяпауза Пропускнаяспособность
Parallel 1681МС 99.3%
G1 351МС 95.9%
cms 283МС 99.2%
Долгожданный победитель
58
Максимальнаяпауза ПРопускнаяспособность
Parallel 1681МС 99.3%
G1 351МС 95.9%
cms 283МС 99.2%
Долгожданный победитель
Оптимизация потребления памяти в Java - делаем уборку правильно

Оптимизация потребления памяти в Java - делаем уборку правильно