Разбор сложных случаев OutOfMemoryError

Preview:

Citation preview

© 2015 NetCracker Technology Corporation Confidential

Разбор сложных случаев OutOfMemoryError

Владимир СитниковJokerconf 2015

2© 2015 NetCracker Technology Corporation Confidential

• Владимир Ситников• Performance engineer @ NetCracker• sitnikov@netcracker.com• @VladimirSitnikv

Кто я

3© 2015 NetCracker Technology Corporation Confidential

О чём доклад

• Разбор некоторых OutOfMemoryError• Примеры подходов к анализу/защите от OOM• OpenJDK/OracleJDK

4© 2015 NetCracker Technology Corporation Confidential

Как понять, что память закончилась?

Видим в логах OutOfMemoryError – значит наш случай• OutOfMemoryError: Java heap space• OutOfMemoryError: heap allocation failed• OutOfMemoryError: PermGen/Metadata space• OutOfMemoryError: unable to create native thread• ...

5© 2015 NetCracker Technology Corporation Confidential

Дело о потерянном процессе

• Java процесс работал и пропал

6© 2015 NetCracker Technology Corporation Confidential

Дело о потерянном процессе

• Java процесс работал и пропал• hs_err файл не появился

7© 2015 NetCracker Technology Corporation Confidential

Дело о потерянном процессе

• Java процесс работал и пропал• hs_err файл не появился• В out, err, log пусто

8© 2015 NetCracker Technology Corporation Confidential

Дело о потерянном процессе

• Java процесс работал и пропал• hs_err файл не появился• В out, err, log пусто• Как так?

9© 2015 NetCracker Technology Corporation Confidential

OOMkiller

У Linux память конечна, и если она заканчивается, то может случиться разное:

• умрёт невезучий процесс (по умолчанию)

10© 2015 NetCracker Technology Corporation Confidential

OOMkiller

У Linux память конечна, и если она заканчивается, то может случиться разное:

• умрёт невезучий процесс (по умолчанию)• malloc вернёт ошибку «нет памяти»

11© 2015 NetCracker Technology Corporation Confidential

OOMkiller

У Linux память конечна, и если она заканчивается, то может случиться разное:

• умрёт невезучий процесс (по умолчанию)• malloc вернёт ошибку «нет памяти»

Ключевое слово в Linux: vm.overcommit_memory=0

12© 2015 NetCracker Technology Corporation Confidential

Смотрим потребление памяти

$ top PID VIRT RES COMMAND18133 9606m 7.3g ora_dbw0_DB1132600 2163m 843m /jdk170_55/bin/java -Xmx200m17532 1757m 602m /jdk160_14/bin/java -Xmx1024m

13© 2015 NetCracker Technology Corporation Confidential

Смотрим потребление памяти

$ top PID VIRT RES COMMAND18133 9606m 7.3g ora_dbw0_DB1132600 2163m 843m /jdk170_55/bin/java -Xmx200m17532 1757m 602m /jdk160_14/bin/java -Xmx1024m$ free –g (http://www.linuxatemyram.com/) total used freeMem: 31 31 0-/+ buffers/cache: 10 21Swap: 8 3 5

Занимаемая память

Свободная память

14© 2015 NetCracker Technology Corporation Confidential

Смотрим потребление памяти

$ top PID VIRT RES COMMAND18133 9606m 7.3g ora_dbw0_DB1132600 2163m 843m /jdk170_55/bin/java -Xmx200m17532 1757m 602m /jdk160_14/bin/java -Xmx1024m

15© 2015 NetCracker Technology Corporation Confidential

Следим за native памятью

• -XX:+NativeMemoryTracking=[off|summary|detail]

16© 2015 NetCracker Technology Corporation Confidential

Следим за native памятью

• -XX:+NativeMemoryTracking=[off|summary|detail]• Работает начиная с 1.7u40

17© 2015 NetCracker Technology Corporation Confidential

Следим за native памятью

• -XX:+NativeMemoryTracking=[off|summary|detail]• Работает начиная с 1.7u40• Получить разбивку можно через

• jcmd <pid> VM.native_memory <output_file_name>• -XX:+PrintNMTStatistics -XX:+UnlockDiagnosticVMOptions• Или JMX: com.sun.management:type=

DiagnosticCommand/vmNativeMemory

18© 2015 NetCracker Technology Corporation Confidential

NMT на практике

19© 2015 NetCracker Technology Corporation Confidential

Ценный мех NMT

NMT позволяет• более адресно заводить тикеты на OpenJDK• проверять наличие утечек «служебной» памятиПример: GROOVY-7498 Groovy native memory leak

20© 2015 NetCracker Technology Corporation Confidential

Накладные расходы

• В 1.7u40 активация NMT замедляет на 5-10%• http://hirt.se/blog/?p=401

• В 1.8u40 вошла доработка масштабируемости NMT• JEP 195: Scalable Native Memory Tracking

21© 2015 NetCracker Technology Corporation Confidential

Запускаем процесс

new ProcessBuilder("ping","123.321.123.321") .start();

22© 2015 NetCracker Technology Corporation Confidential

Запускаем процесс

new ProcessBuilder("ping", "8.8.8.8") .start();

23© 2015 NetCracker Technology Corporation Confidential

24© 2015 NetCracker Technology Corporation Confidential

На самом деле, можно

Если версия JDK свежая, то проблем нет:• https://bugs.openjdk.java.net/browse/JDK-5049299• 1.7u60+ всё ок• 1.8u??+ (в 8u60 исправление есть наверняка)

25© 2015 NetCracker Technology Corporation Confidential

В предыдущих серияхверсиях

• ProcessBuilder#start() использует fork()

• -Xmx8g «по наследству» передаётся в ping• В итоге ping либо не запустится, либо есть

шанс разбудить oomkiller

26© 2015 NetCracker Technology Corporation Confidential

Как запускать процессы в OpenJDK<1.7u60

• Либо вообще не запускать процессы

27© 2015 NetCracker Technology Corporation Confidential

Как запускать процессы в OpenJDK<1.7u60

• Либо вообще не запускать процессы• Либо использовать jnr-posix (напрямую или из JRuby)

• https://github.com/jnr/jnr-posix

28© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: unable to create native thread

• Кто виноват?

29© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: unable to create native thread

• Кто виноват?• 32bit JVM и в адресном пространстве уже негде выделить место для

стека (thread native stack)

30© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: unable to create native thread

• Кто виноват?• 32bit JVM и в адресном пространстве уже негде выделить место для

стека (thread native stack)

• Что делать?• Переходить на 64bit JVM

31© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: unable to create native thread

• Кто виноват?• 32bit JVM и в адресном пространстве уже негде выделить место для

стека (thread native stack)

• Что делать?• Переходить на 64bit JVM• Или уменьшать -XX:ThreadStackSize, уменьшать -XX:MaxPermSize

32© 2015 NetCracker Technology Corporation Confidential

А какая у нас версия?

$ java -Xmx800m -versionError occurred during initialization of VMjava.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:714) at java.lang.ref.Finalizer.<clinit>(Finalizer:226)

33© 2015 NetCracker Technology Corporation Confidential

limits

$ ulimit –a

34© 2015 NetCracker Technology Corporation Confidential

limits

$ ulimit –avirtual memory (kbytes, -v) unlimited

35© 2015 NetCracker Technology Corporation Confidential

limits

$ ulimit –avirtual memory (kbytes, -v) unlimitedopen files (-n) 16384

36© 2015 NetCracker Technology Corporation Confidential

limits

$ ulimit –avirtual memory (kbytes, -v) unlimitedopen files (-n) 16384max user processes (-u) 100000

37© 2015 NetCracker Technology Corporation Confidential

limits

$ ulimit –avirtual memory (kbytes, -v) unlimitedopen files (-n) 16384max user processes (-u) 100000stack size (kbytes, -s) 10240

38© 2015 NetCracker Technology Corporation Confidential

Действия в случае OutOfMemoryError

try { "основной_монитор".notifyAll();} catch (OutOfMemoryError e) { log.info("Нужно больше памяти", e);}

39© 2015 NetCracker Technology Corporation Confidential

Действия в случае OutOfMemoryError

try { "основной_монитор".notifyAll();} catch (OutOfMemoryError e) { log.info("Нужно больше памяти", e);}

40© 2015 NetCracker Technology Corporation Confidential

Реальные проблемы

• OOM может получить любой поток в любой момент времени

41© 2015 NetCracker Technology Corporation Confidential

Реальные проблемы

• OOM может получить любой поток в любой момент времени

• Например, ReentrantLock в момент unlock

42© 2015 NetCracker Technology Corporation Confidential

Реальные проблемы

• OOM может получить любой поток в любой момент времени

• Например, ReentrantLock в момент unlock

• И мы получим вечнозанятую блокировку, сломанную ArrayBlockingQueue, …

43© 2015 NetCracker Technology Corporation Confidential

Реальные проблемы

• OOM может получить любой поток в любой момент времени

• Например, ReentrantLock в момент unlock• И мы получим вечнозанятую блокировку,

сломанную ArrayBlockingQueue, …• Аналогично и в случае StackOverflowError

44© 2015 NetCracker Technology Corporation Confidential

В случае аварии

В случае OutOfMemoryError/StackOverflowError гораздо правильнее делать так:• System.exit(146)• -XX:OnError="kill -9 %p"

45© 2015 NetCracker Technology Corporation Confidential

Java heap

• Хранит java объекты, их содержимое

46© 2015 NetCracker Technology Corporation Confidential

Java heap

• Хранит java объекты, их содержимое

• Очищается сборщиком мусора

47© 2015 NetCracker Technology Corporation Confidential

Java heap

• Хранит java объекты, их содержимое

• Очищается сборщиком мусора

• Бывает, заканчивается

48© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: PermGen space

• Кто виноват?• Размер PermGen слишком мал• Загружено слишком много классов

49© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: PermGen space

• Кто виноват?• Размер PermGen слишком мал• Загружено слишком много классов

• Что делать?• Увеличивать perm gen: -XX:PermSize=512M -XX:MaxPermSize=512M

• Искать лишние классы: jmap –histo

50© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: PermGen space

• Кто виноват?• Размер PermGen слишком мал• Загружено слишком много классов

• Что делать?• Увеличивать perm gen: -XX:PermSize=512M -XX:MaxPermSize=512M

• Искать лишние классы: jmap –histo• Обновлять java (в 8-ке будет ошибка Metadata space:)

51© 2015 NetCracker Technology Corporation Confidential

OutOfMemoryError: Java heap space

• Кто виноват?• Выделено мало памяти• Garbage Collector не успел собрать мусор

• Что делать?• Выделять больше памяти: -Xms, -Xmx• Анализировать использование памяти

52© 2015 NetCracker Technology Corporation Confidential

Как анализировать занятость heap

GC log фиксирует приход-расход памяти по времени

53© 2015 NetCracker Technology Corporation Confidential

Как анализировать занятость heap

GC log фиксирует приход-расход памяти по времени

• Как собрать: -Xloggc:logs/gc.log, -XX:+PrintGCDetails, и т.д.

54© 2015 NetCracker Technology Corporation Confidential

Как анализировать занятость heap

GC log фиксирует приход-расход памяти по времени

• Как собрать: -Xloggc:logs/gc.log, -XX:+PrintGCDetails, и т.д.

• Чем смотреть: GCViewer

55© 2015 NetCracker Technology Corporation Confidential

Как анализировать занятость heap

GC log фиксирует приход-расход памяти по времени

• Как собрать: -Xloggc:logs/gc.log, -XX:+PrintGCDetails, и т.д.

• Чем смотреть: GCViewer

• На что смотреть: «занятость памяти после full gc»

56© 2015 NetCracker Technology Corporation Confidential

GC лог здорового человека

• 60мс minor, 3sec major паузы

57© 2015 NetCracker Technology Corporation Confidential

GC лог курильщика

• Сплошные full gc

58© 2015 NetCracker Technology Corporation Confidential

Недоперепил

• Бывает, памяти остаётся мало• GC постоянно как-то находит крохи мусора

59© 2015 NetCracker Technology Corporation Confidential

Недоперепил

• Бывает, памяти остаётся мало• GC постоянно как-то находит крохи мусора• А OutOfMemory всё нет и нет!

60© 2015 NetCracker Technology Corporation Confidential

Недоперепил

• Бывает, памяти остаётся мало• GC постоянно как-то находит крохи мусора• А OutOfMemory всё нет и нет!• Что делать, шеф?

61© 2015 NetCracker Technology Corporation Confidential

Варианты действий, когда почти OOM

• Jmap – снимать дамп вручную

62© 2015 NetCracker Technology Corporation Confidential

Варианты действий, когда почти OOM

• Jmap – снимать дамп вручную• GC overhead limit

63© 2015 NetCracker Technology Corporation Confidential

Варианты действий, когда почти OOM

• Jmap – снимать дамп вручную• GC overhead limit

• -XX:GCHeapFreeLimit=20 (2 по умолчанию)‒ Если после full GC останется меньше X%, то OOM

64© 2015 NetCracker Technology Corporation Confidential

Варианты действий, когда почти OOM

• Jmap – снимать дамп вручную• GC overhead limit

• -XX:GCHeapFreeLimit=20 (2 по умолчанию)‒ Если после full GC останется меньше X%, то OOM

• -XX:GCTimeLimit=Y (98 по умолчанию)‒Если сборка мусора занимает более Y%

времени, то OOM

65© 2015 NetCracker Technology Corporation Confidential

Чисто там, где не мусорят

• Java Flight Recorder / Java Mission Control

66© 2015 NetCracker Technology Corporation Confidential

Как понять, кто создаёт объекты?

Java Flight Recorder• Позволяет узнать stack trace где создавались объекты• Позволяет узнать объём выделяемой памяти

67© 2015 NetCracker Technology Corporation Confidential

Как понять, кто создаёт объекты?

Java Flight Recorder• Позволяет узнать stack trace где создавались объекты• Позволяет узнать объём выделяемой памяти• Бесплатно на test серверах

68© 2015 NetCracker Technology Corporation Confidential

Как понять, кто создаёт объекты?

Java Flight Recorder• Позволяет узнать stack trace где создавались объекты• Позволяет узнать объём выделяемой памяти• Бесплатно на test серверах

Запуск:

• -XX:+UnlockCommercialFeatures -XX:+FlightRecorder-XX:FlightRecorderOptions=repository=jfr,defaultrecording=false

69© 2015 NetCracker Technology Corporation Confidential

Как понять, кто создаёт объекты?

Java Flight Recorder• Позволяет узнать stack trace где создавались объекты• Позволяет узнать объём выделяемой памяти• Бесплатно на test серверах

Запуск:

• -XX:+UnlockCommercialFeatures -XX:+FlightRecorder-XX:FlightRecorderOptions=repository=jfr,defaultrecording=false

• jcmd <pid> JFR.start duration=2m filename=logs/myrecording.jfr settings=profile stackdepth=2000

70© 2015 NetCracker Technology Corporation Confidential

OOM: heap space

Дамп памяти содержит снимок содержимого java heap• Как собрать: -XX:HeapDumpOnOutOfMemoryError

71© 2015 NetCracker Technology Corporation Confidential

OOM: heap space

Дамп памяти содержит снимок содержимого java heap• Как собрать: -XX:HeapDumpOnOutOfMemoryError• jmap -dump

72© 2015 NetCracker Technology Corporation Confidential

OOM: heap space

Дамп памяти содержит снимок содержимого java heap• Как собрать: -XX:HeapDumpOnOutOfMemoryError• jmap -dump• jmap -dump -F (force режим, если обычный не работает)

73© 2015 NetCracker Technology Corporation Confidential

OOM: heap space

Дамп памяти содержит снимок содержимого java heap• Как собрать: -XX:HeapDumpOnOutOfMemoryError• jmap -dump• jmap -dump -F (force режим, если обычный не работает)• Чем смотреть: Eclipse Memory Analyzer, VisualVM, jol, jvm-tools

74© 2015 NetCracker Technology Corporation Confidential

75© 2015 NetCracker Technology Corporation Confidential

Скорость работы jmap

$jmap –dump .. real 0m7.992suser 0m0.304ssys 0m0.067s

$ jmap –dump –F ..real 24m4.378suser 21m56.321ssys 6m51.676s

76© 2015 NetCracker Technology Corporation Confidential

В тяжёлых случаях

• core dump быстрее и надёжнее чем jmap -dump <pid>$ ulimit –ccore file size (blocks, -c) 33’222’111

77© 2015 NetCracker Technology Corporation Confidential

В тяжёлых случаях

• core dump быстрее и надёжнее чем jmap -dump <pid>$ ulimit –ccore file size (blocks, -c) 33’222’111

• Из core dump можно получить hprof (через jmap …)

78© 2015 NetCracker Technology Corporation Confidential

• Дамп памяти содержит данные всех объектов• Состояние потоков (thread dump)• Значения локальных переменных

Дампы памяти

79© 2015 NetCracker Technology Corporation Confidential

• Дамп памяти содержит данные всех объектов• Состояние потоков (thread dump)• Значения локальных переменных

Дампы памяти

Да, пароли там тоже есть

80© 2015 NetCracker Technology Corporation Confidential

• -Xmx2G, OracleJDK 1.8u60

java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid59998.hprof ...Heap dump file created [1’650’484 bytes in 0.023 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at Demo1.main(Demo1.java:6)

Маловато будет

81© 2015 NetCracker Technology Corporation Confidential

• -Xmx2G, OracleJDK 1.8u60

java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid59998.hprof ...Heap dump file created [1’650’484 bytes in 0.023 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at Demo1.main(Demo1.java:6)

Маловато будет

long len = Runtime.getRuntime().maxMemory();long[] array = new long[(int) len]; Demo1.java:6

82© 2015 NetCracker Technology Corporation Confidential

Терминология

«утекла память», «потребилась память»== кто-то мешает GC её освободить

83© 2015 NetCracker Technology Corporation Confidential

Кто может держать память?

• Потоки (threads)

84© 2015 NetCracker Technology Corporation Confidential

Кто может держать память?

• Потоки (threads)• Локальные переменные

85© 2015 NetCracker Technology Corporation Confidential

Кто может держать память?

• Потоки (threads)• Локальные переменные• Кишки JVM

86© 2015 NetCracker Technology Corporation Confidential

Кто может держать память?

• Потоки (threads)• Локальные переменные• Кишки JVM• И далее по цепочкам простых ссылок,

WeakReferences, SoftReferences, PhantomReferences

87© 2015 NetCracker Technology Corporation Confidential

Кто может держать память?

• Потоки (threads)• Локальные переменные• Кишки JVM• И далее по цепочкам простых ссылок,

WeakReferences, SoftReferences, PhantomReferences, FinalReferences

‾√

88© 2015 NetCracker Technology Corporation Confidential

‾√

WeakHashMap<K, V>

K1 V1

K2 V2

89© 2015 NetCracker Technology Corporation Confidential

‾√

WeakHashMap<K, V>

K1 V1

K2 V2

90© 2015 NetCracker Technology Corporation Confidential

‾√

WeakHashMap<K, V>

91© 2015 NetCracker Technology Corporation Confidential

WeakHashMap<K, V>

K1 V1

K2 V2√‾

92© 2015 NetCracker Technology Corporation Confidential

WeakHashMap<K, V>

K1 V1

K2 V2√‾

93© 2015 NetCracker Technology Corporation Confidential

И освободится ли WeakHashMap<K, V>?

K1 V1

K2 V2?√‾

94© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

95© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

96© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

97© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

98© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

99© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

100© 2015 NetCracker Technology Corporation Confidential

√‾

Освобождению не подлежит

K1 V1

K2 V2

101© 2015 NetCracker Technology Corporation Confidential

И кто же так делает?

• XML element• Элемент хранит ссылку на документ, а тот на всё

остальное

102© 2015 NetCracker Technology Corporation Confidential

И кто же так делает?

• XML element• Элемент хранит ссылку на документ, а тот на всё

остальное

• java.beans.…

103© 2015 NetCracker Technology Corporation Confidential

Пример из жизни

• Запускаем Groovy

104© 2015 NetCracker Technology Corporation Confidential

Пример из жизни

• Запускаем Groovy• Из JSR223 API (scripting API)

105© 2015 NetCracker Technology Corporation Confidential

Пример из жизни

• Запускаем Groovy• Из JSR223 API (scripting API)• И получаем OutOfMemoryError

106© 2015 NetCracker Technology Corporation Confidential

Терминология

Для любого объекта Ы есть 2 основных метрики• Shallow heap – объём памяти, занимаемый самим

объектом• Retained heap – объём памяти, который освободится,

если Ы окажется мусором

107© 2015 NetCracker Technology Corporation Confidential

Dominator tree

2 3

4 5

№2 не доминирует №3

№4 доминирует №5

√‾

108© 2015 NetCracker Technology Corporation Confidential

Groovy + Scripting for Java (JSR 223) = печаль (demo1)

Демо: groovy

109© 2015 NetCracker Technology Corporation Confidential

Dominator Tree (demo1)• Показывает объекты, которые держат больше всего других

110© 2015 NetCracker Technology Corporation Confidential

Разбираем строку в число

* http://shipilev.net/blog/2014/exceptional-performance

static long toLongFast(char[] c) throws IllegalArgumentException { if (c.length == 1) return c[0] - '0'; // Пусть с дробными разбираются другие throw new IllegalArgumentException(); *}

111© 2015 NetCracker Technology Corporation Confidential

Так быстрее, но не утечёт ли память? static final IllegalArgumentException CFE = new IllegalArgumentException();

static long toLongFast(char[] c) throws IllegalArgumentException { if (c.length == 1) return c[0] - '0'; throw CFE;

112© 2015 NetCracker Technology Corporation Confidential

Throwable наносит ответный удар

• StackTraceElement это сплошные строки, но в Throwable есть скрытое поле backtrace

113© 2015 NetCracker Technology Corporation Confidential

Throwable наносит ответный удар

• StackTraceElement это сплошные строки, но в Throwable есть скрытое поле backtrace

• Оно прекрасно держит ссылки на классы из стектрейса

114© 2015 NetCracker Technology Corporation Confidential

Throwable наносит ответный удар

• StackTraceElement это сплошные строки, но в Throwable есть скрытое поле backtrace

• Оно прекрасно держит ссылки на классы из стектрейса• Иногда это может быть неожиданной ссылкой на класс

115© 2015 NetCracker Technology Corporation Confidential

Мораль

• Либо не используем «ControlFlowException»• Либо не заполняем stacktrace

static final IllegalArgumentException CFE = new IllegalArgumentException() { public Throwable fillInStackTrace() { return this; } }

116© 2015 NetCracker Technology Corporation Confidential

Object#finalize

Не стоит использовать finalizer’ы для «освобождения ресурсов»

• Finalizable объекты живут на 1 цикл GC (падают в old gen, ужас-ужас)

117© 2015 NetCracker Technology Corporation Confidential

Object#finalize

Не стоит использовать finalizer’ы для «освобождения ресурсов»

• Finalizable объекты живут на 1 цикл GC (падают в old gen, ужас-ужас)

• Невозможно объяснить JVM, что объект не надо финализировать (если вручную вызвали .close)

118© 2015 NetCracker Technology Corporation Confidential

Object#finalize -> PhantomReference

PhantomReference позволяет организовать «автоматическое освобождение ресурсов» с поддержкой ручного:

• PhantomReference сохраняется в какую-нибудь map/set

119© 2015 NetCracker Technology Corporation Confidential

Object#finalize -> PhantomReference

PhantomReference позволяет организовать «автоматическое освобождение ресурсов» с поддержкой ручного:

• PhantomReference сохраняется в какую-нибудь map/set

• Если объект выходит из видимости, GC обрабатывает Phantom

120© 2015 NetCracker Technology Corporation Confidential

Object#finalize -> PhantomReference

PhantomReference позволяет организовать «автоматическое освобождение ресурсов» с поддержкой ручного:

• PhantomReference сохраняется в какую-нибудь map/set

• Если объект выходит из видимости, GC обрабатывает Phantom

• Если пользователь закрыл объект вручную, то там же и очищается Phantom

121© 2015 NetCracker Technology Corporation Confidential

PhantomReference Map<Reference<Statement>, String> resources;ReferenceQueue<Statement> queue = new ReferenceQueue<>();

public void autoCleanup() throws Throwable { PreparedStatement ps = con.prepareStatement("select 1"); PhantomReference<Statement> ref = new PhantomReference<>(ps, queue); resources.put(ref, "name");

/* В методе .close(): */ ref.clear();}

122© 2015 NetCracker Technology Corporation Confidential

На практике

• PostgreSQL JDBC драйвер pgjdbc использовал Statement#finalize

• @Benchmark на «создание statement» падал с OOM• После исключения finalize, стало 45ns/create даже

при 100% утекании (т.е. без ручных вызовов close):https://github.com/pgjdbc/pgjdbc/pull/299

123© 2015 NetCracker Technology Corporation Confidential

• @shipilёv: не все хипдампы одинаково полезны

Eclipse Memory Analyzer

124© 2015 NetCracker Technology Corporation Confidential

Puzzler

++i--Что это?

125© 2015 NetCracker Technology Corporation Confidential

Puzzler

++i--^^^ оператор подёргивания

126© 2014 NetCracker Technology Corporation Confidential

Демо

127© 2015 NetCracker Technology Corporation Confidential

Dominator Tree (demo2)

• Quiz: Может ли объект дважды попасть в Dominator Tree?

128© 2015 NetCracker Technology Corporation Confidential

Основные окна Eclipse MAT (demo2)

• Class Histogram• Показывает суммарную информацию по классам

129© 2015 NetCracker Technology Corporation Confidential

Dominator Tree (demo2)

• Как не погрязнуть в вечном разворачивании плюсиков?

130© 2015 NetCracker Technology Corporation Confidential

Алгоритм анализа дампов в Eclipse MAT

• Retained Set• Immediate Dominators

131© 2015 NetCracker Technology Corporation Confidential

Алгоритм анализа дампов в Eclipse MAT

• Dominator Tree• Retained Set• Immediate Dominators

132© 2015 NetCracker Technology Corporation Confidential

Алгоритм анализа дампов в Eclipse MAT

• Dominator Tree• Retained Set• Immediate Dominators• Retained Set• Immediate Dominators• Retained Set

• Immediate Dominators

133© 2015 NetCracker Technology Corporation Confidential

Dominator Tree

• “Show Retained Set” показывает плоский список удерживаемых объектов

134© 2015 NetCracker Technology Corporation Confidential

Immediate dominators

• Кто-то очень любит HashMap$Entry. Как узнать кто?

• Immediate dominators!

135© 2015 NetCracker Technology Corporation Confidential

HashMap$Entry

• Если очень захотеть, то можно сделать Map с накладными расходами в 4 байта на запись

136© 2015 NetCracker Technology Corporation Confidential

HashMap

HashMap Entry[]

Entryid

41

Entryname

qwe

137© 2015 NetCracker Technology Corporation Confidential

HashMap: entry лишние

HashMap Entry[]

Entryid

41

Entryname

qwe

138© 2015 NetCracker Technology Corporation Confidential

HashMap

HashMap Entry[]

Entryid

41

Entryname

qwe

139© 2015 NetCracker Technology Corporation Confidential

CompactMap

CMap1 Object[]41

qwe

CMap2

keyposid=0

name=1

Object[]42

rty

140© 2015 NetCracker Technology Corporation Confidential

HashMap$Entry

• Работает, если форма (состав ключей) у многих объектов одинаковая• Например, у всех объектов есть запись “width”=“100%”

141© 2015 NetCracker Technology Corporation Confidential

HashMap$Entry

• Работает, если форма (состав ключей) у многих объектов одинаковая• Например, у всех объектов есть запись “width”=“100%”

• https://github.com/vlsi/compactmap• См. v8/design.html#prop_access

142© 2015 NetCracker Technology Corporation Confidential

CompactHashMap

HashMap -> CompactHashMap в реальном проекте:

• 500МиБ –> 290МиБ• 3.0 сек / 1M обращений -> 150 сек / 1M обращений

143© 2015 NetCracker Technology Corporation Confidential

CompactHashMap

HashMap -> CompactHashMap в реальном проекте:

• 500МиБ –> 290МиБ• 3.0 сек / 1M обращений -> 150 сек / 1M обращений

144© 2015 NetCracker Technology Corporation Confidential

ReservedCodeCacheSize

• Если у JIT компилятора заканчивается память, то он перестаёт компилировать

145© 2015 NetCracker Technology Corporation Confidential

ReservedCodeCacheSize

• Если у JIT компилятора заканчивается память, то он перестаёт компилировать

• В Weblogic/EE/… стандартных 64M мало

146© 2015 NetCracker Technology Corporation Confidential

ReservedCodeCacheSize

• Если у JIT компилятора заканчивается память, то он перестаёт компилировать

• В Weblogic/EE/… стандартных 64M мало• -XX:+ReservedCodeCacheSize=128m/192m

147© 2015 NetCracker Technology Corporation Confidential

CompactHashMap

HashMap -> CompactHashMap, -XX:+ReservedCodeCacheSize=128m:

• 500МиБ –> 290МиБ• 3.0 сек / 1M обращений -> 3.5 сек / 1M обращений

148© 2015 NetCracker Technology Corporation Confidential

Но как же автоматизация?

• В Eclipse есть Object Query Language

149© 2015 NetCracker Technology Corporation Confidential

Но как же автоматизация?

• В Eclipse есть Object Query Language• В простых случаях даже работает

150© 2015 NetCracker Technology Corporation Confidential

Но как же автоматизация?

• В Eclipse есть ограниченный :( Object Query Language• Нет group by• Нет join• Нет distinct

151© 2015 NetCracker Technology Corporation Confidential

OQL!

• В Eclipse есть ограниченный :( Object Query Language• Нет group by• Нет join• Нет distinct

• Может, оно и не нужно?

152© 2015 NetCracker Technology Corporation Confidential

Примеры, когда OQL пасует

• Если в одной коллекции хранятся разнородные данные, то OQL не подходит• EJB bean cache• Свои кэши данных

• Если данные разбиты по разным java-объектам, то OQL не подходит

153© 2015 NetCracker Technology Corporation Confidential

Ты ж программист

• Берём SQL engine: Apache Calcite

154© 2015 NetCracker Technology Corporation Confidential

Ты ж программист

• Берём SQL engine: Apache Calcite• Прикручиваем его к MAT: mat-calcite-plugin

155© 2015 NetCracker Technology Corporation Confidential

Ты ж программист

• Берём SQL engine: Apache Calcite• Прикручиваем его к MAT: mat-calcite-plugin• Получаем:

• JOIN, WHERE, GROUP BY, ORDER BY, HAVING• UNION, INTERSECT• Подзапросы• Аналитические функции (WINDOW, OVER)

156© 2015 NetCracker Technology Corporation Confidential

Пример SQL

-- Tables:-- "java.lang.BigInteger" list of all BigIntegers-- "instanceof java.lang.BigInteger" BigIntegers and all

select u."@THIS", s."@RETAINED" from "java.lang.String" s , "java.net.URL" u where s."@THIS" = u.path

157© 2015 NetCracker Technology Corporation Confidential

Mat-calcite-plugin

• Плюсы:• Хорошая поддержка SQL• Ставится из MAT (“install new software…”)

158© 2015 NetCracker Technology Corporation Confidential

Mat-calcite-plugin

• Плюсы:• Хорошая поддержка SQL• Ставится из MAT (“install new software…”)

• Минусы:• Подходит не для каждого запроса: Calcite заточен

под full scan• Обход графа на SQL это та ещё радость

159© 2015 NetCracker Technology Corporation Confidential

VisualVM

• VisualVM UI работает неторопливо, но OQL позволяет выполнять javascript map-reduce

• Распечатка System.properties:

select map(filter(heap.findClass('java.lang.System').props.table , 'it != null && it.key != null && it.value != null') , function (it) { var res = it.key.toString() + ' = ' + it.value.toString(); return res; });

160© 2015 NetCracker Technology Corporation Confidential

aragozin/jvm-tools

• На очень больших дампах, dominator tree построить невозможно

• В таких случаях поможет HeapPath из состава aragozin/jvm-tools:• field1.field2.field3.*.field4• arrayField[0].arrayField2[*].field5• hashMap?entrySet[key=name].value

161© 2015 NetCracker Technology Corporation Confidential

Ты ж java программист

• Java object layout хорошо подходит для анализа индивидуальных объектов:http://hg.openjdk.java.net/code-tools/jol/…/samples/

162© 2015 NetCracker Technology Corporation Confidential

Ты ж java программист

• Java object layout хорошо подходит для анализа индивидуальных объектов:http://hg.openjdk.java.net/code-tools/jol/…/samples/

• Плюсы:• Управляется из java кода• Выдаёт точные значения

163© 2015 NetCracker Technology Corporation Confidential

Ты ж java программист

• Java object layout хорошо подходит для анализа индивидуальных объектов:http://hg.openjdk.java.net/code-tools/jol/…/samples/

• Плюсы:• Управляется из java кода• Выдаёт точные значения

• Минусы:• Управляется из java кода

164© 2015 NetCracker Technology Corporation Confidential

Выводы

• До OOM стараемся не доводить (-Xmx, thread pools, и т.п.)

• Если довели, то снимаем хипдамп (jmap, coredump)

• Обновляем JVM ради: исправления ошибок, инструментария

165© 2015 NetCracker Technology Corporation Confidential

• Владимир Ситников• Performance engineer @ NetCracker• sitnikov@netcracker.com• @VladimirSitnikv

Спасибо

Спасибо

166© 2015 NetCracker Technology Corporation Confidential

Recommended