Чёрная магия JIT компиляции · Чёрная магия JIT компиляции Алексей Рагозин [email protected]
DUMP-2012 - Только хардкор! - "Секреты сборки мусора в Java"...
Transcript of DUMP-2012 - Только хардкор! - "Секреты сборки мусора в Java"...
Секреты сборки мусора в Секреты сборки мусора в JavaJava
Алексей Рагозин[email protected]
О чём этот доклад?О чём этот доклад?
• Обзор проблемы автоматического управления памятью
• Stop-the-world паузы – причины• Сборка мусора в современных JVM
Сборка мусораСборка мусора
Языки использующие автоматическое управление памятью Java, JavaScript, Erlang, Haskell, Python, PHP, C#, Ruby, Perl, SmallTalk, OCaml, List, Scala, ML, Go, D, … … and counting
Языки не использующие автоматическое управление памятью C, C++, Pascal/Delphi, Objective-C Что я забыл?
Способы сборки мусораСпособы сборки мусораМусор – структура данных (объект) в памяти не достижимый из программного кода.
Подсчёт ссылокТранзитивное замыкание ссылок Вообще не собирать
Подсчёт ссылокПодсчёт ссылок
+ Просто+ Не требует пауз для сбора мусора– Не очищает циклические графы– Дополнительные 15-30% нагрузки CPU– Плохо сочетается с много поточностью
Транзитивное замыкание Транзитивное замыкание ссылокссылок
• Корневой набор ссылок Статические переменные Локальные переменные
• Объекты достижимые из корневых ссылок – живые• Объекты недостижимые из корневых ссылок – мусор
В общем случае, граф объектов не должен меняться по мере обхода. Следовательно, прикладные потоки должны быть остановлены пока идёт сборка мусора.
Алгоритмы сборки мусораАлгоритмы сборки мусора
• Mark-Sweep Фаза 1 – маркировка достижимых объектов Фаза 2 – “вычистка” мусора
• Copy collector (сборка копированием) Использует две области памяти, но выполняется в один проход
• Mark-Sweep-Compact Mark-Sweep + перемещение живых объектов
Трёх цветная маркировкаТрёх цветная маркировка
roots
Трёх цветная маркировкаТрёх цветная маркировка
roots
roots
Трёх цветная маркировкаТрёх цветная маркировка
roots
roots
Трёх цветная маркировкаТрёх цветная маркировка
roots
roots
Сборка копированиемСборка копированием
FROM
TO
roots
Сборка копированиемСборка копированием
FROM
TO
roots
FROM
TO
roots
Сборка копированиемСборка копированием
FROM
TO
roots
FROM
TO
roots
1
Сборка копированиемСборка копированием
FROM
TO
roots
FROM
TO
roots
1 2
Сборка копированиемСборка копированием
FROM
TO
roots
FROM
TO
roots
1 2
Сборка копированиемСборка копированием
FROM
TO
roots
FROM
TO
roots
1 23
Экономика сборки мусораЭкономика сборки мусораS – объём кучиL – объём живых объектов
Copy collection ЭффективностьMark-Sweep Эффективность
L
LSc
S
LSc
L
LSc
21
Объём мусора в куче
Слабая гипотеза о поколенияхСлабая гипотеза о поколениях
Постулаты Большинство объектов умирают молодыми Число ссылок на молодые объекты мало
СледствиеЕсли хранить молодые объекты отдельно от старых, можно
обеспечить высокую пропускную способность (молодое поколение) и эффективное использование памяти (старое поколение).
Демография объектов в кучеДемография объектов в куче
См
ертн
ость
(б
айт/
с)
Возраст объектов
Период молодой сборки
Период старой сборки
∞
Generational collectionGenerational collection Молодое поколение
Сборщик настроен на пропускную способность Старое поколение
Сборщик настроен на эффективное использование памяти Продвижение (promotion) объектов в старое поколение
Сборщик молодого поколения копирует живые объекты в старое поколение после достижения “зрелого” возраста
Generational collectionGenerational collection
Как получить все указатели из старого поколения на молодое?Ответ – барьер на записьКаждый раз при записи указателя в память в “старом” пространстве, срабатывает барьер
Молодая сборка Молодая сборка HotSpot JVMHotSpot JVM
Eden S1 S2 Tenured
Dirty cards
Collect roots for young GCScan stack tracesScan dirty pages in old space
Сбор Сбор ““корневыхкорневых”” ссылок ссылок
Молодая сборка Молодая сборка HotSpot JVMHotSpot JVM
Eden S1 S2 Tenured
Dirty cards
Collect roots for young GCClean cardsRecursive copy of live objects (only live objects are traversed)
Копирование живых объектовКопирование живых объектов
Молодая сборка Молодая сборка HotSpot JVMHotSpot JVM
Eden S1 S2 Tenured
Dirty cards
Сборка законченаСборка закончена
Области памяти, не помеченные в таблице карт, не могут содержать ссылки на молодое поколение
Stop-the-world Stop-the-world паузыпаузы
• Изменение графа объектов во время обхода может привести к пропуску достижимых объектов
• Большинство managed runtimes может перемещать объекты только в режиме паузы
Stop-the-world Stop-the-world паузыпаузы
Параллельные (parallel) алгоритмы Используют несколько потоков чтобы сократить время пауз
Фоновые (concurrent) алгоритмы Выполняют большую часть работы в фоновом режиме (без STW пауз)
Инкрементальные алгоритмы Много маленьких STW вместо одной длительной
Фоновая маркировкаФоновая маркировкаПроблема Граф объектов меняется по мере обхода * * Даже в функциональных языках могут выполняться отложенные вычисления, меняющие граф
Решение барьер на запись – отслеживать ссылки изменившиеся за время обхода
Фоновая маркировкаФоновая маркировка Card marking write barrier
HotSpot CMS, JRockit, IBM J9 Snapshot-at-the-beginning (SATB) write barrier
HotSpot G1 Альтернатива барьеру на запись – барьер на
чтение Azul Zing JVM
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC A
C
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC C
D
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC C
D
Reference queue: B DОчередь ссылок:
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC C
D
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC D
D
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC
Reference queue: B DОчередь ссылок:
SATB SATB барьер записибарьер записи (G1) (G1)
A B C D
GC
Reference queue:
B
D
emptyОчередь ссылок: пусто
““Card marking” Card marking” барьер записибарьер записи
[пауза] Сбор корневых ссылок [фон] Обход графа объектов [фон] Перемаркирова “грязных” страниц [паузa] Финальная перемаркирова
Перемещение объектовПеремещение объектов
Большинство JVM не может перемещать объекты без STW паузы.
Цель – уменьшение длительности паузПараллельная обработка (задействовать все ядра)Инкрементальное уплотнение (чаще, но короче)Не уплотнять – опасность фрагментации
Oracle HotSpotOracle HotSpotОднопоточный сборщик мусора-XX:+UseSerialGCМолодое поколение:• Сборка копированиемСтарое поколение:• Mark Sweep CompactВозвращает неиспользуемую
память ОС после сборки старшего поколения
http://aragozin.blogspot.com/2011/09/hotspot-jvm-garbage-collection-options.html
Oracle HotSpotOracle HotSpotПараллельный сборщик мусора-XX:+UseParallelGC –XX:+UseParallelOldGCМолодое поколение:• Многопоточная сборка копированиемСтарое поколение:• Многопоточный Mark Sweep Compact
http://aragozin.blogspot.com/2011/09/hotspot-jvm-garbage-collection-options.html
Oracle HotSpotOracle HotSpotФоновый сборщик мусора-XX:+UseConcMarkSweepGCМолодое поколение:• Одно или многопоточная сборка копированиемСтарое поколение:• Фоновая Mark Sweep сборкаНе перемещает объекты в старом поколении при сборке в
фоновом режиме
http://aragozin.blogspot.com/2011/09/hotspot-jvm-garbage-collection-options.html
Oracle HotSpotOracle HotSpotФоновый сборщик мусора-XX:+UseG1GCМолодое поколение:• Многопоточная сборка копированиемСтарое поколение:• Инкрементальная многопоточная сборка копированиемВозвращает не используемую память ОС
http://aragozin.blogspot.com/2011/09/hotspot-jvm-garbage-collection-options.html
Oracle’s HotSpot JVMOracle’s HotSpot JVM
Young collector Old collector JVM option Serial (DefNew) Serial Mark-Sweep-Compact -XX:+UseSerialGC
Parallel scavenge (PSYoungGen) Serial Mark-Sweep-Compact (PSOldGen) -XX:+UseParallelGC
Parallel scavenge (PSYoungGen) Parallel Mark-Sweep-Compact (ParOldGen) -XX:+UseParallelOldGC
Serial (DefNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC -XX:-UseParNewGC
Parallel (ParNew) Concurrent Mark Sweep -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
G1 -XX:+UseG1GC
http://blog.ragozin.info/2011/09/hotspot-jvm-garbage-collection-options.html
Oracle JRockitOracle JRockit
-Xgc: option Generational Mark Sweep/Compact
genconcon or gencon Yes concurrent incrementalsingleconcon or singlecon No concurrent incremental
genconpar Yes concurrent parallelsingleconpar No concurrent parallelgenparpar or genpar Yes parallel parallelsingleparpar or singlepar No parallel parallel
genparcon Yes parallel incrementalsingleparcon No parallel incremental
http://blog.ragozin.info/2011/07/jrockit-gc-in-action.html
IBM J9IBM J9-Xgcpolicy:optthruput Одно поколение, stop-the-world сборщик
-Xgcpolicy:optavgpause Одно поколение, частично конкурентный сборщик
-Xgcpolicy:gencon Два поколения, частично конкурентный сборщик
Azul ZingAzul Zing• Два поколения• Молодое поколение – конкурентный mark-sweep-compact
(MSC)• Старое поколение – конкурентный mark-sweep-compact (MSC)
Azul Zing выполняет перемещение объектов (уплотнение памяти) без останова приложения. Ни одна из фаз сборки мусора не требует STW паузы.
Секрет – read barrier (барьер чтения).
Масштабируемость Масштабируемость JVMJVM
Может ли JVM работать с большим объёмом памяти (16GiB и более) без “фризов”?
Ответ да, если приложение удовлетворяет постулатам гипотезы о поколениях.
Рецепт работы без паузРецепт работы без пауз
• HotSpot JVM• CMS (Concurrent Mark Sweep) сборщик
мусора• ТюнингРезультат• Паузы не более 150ms на 32GiB кучи
HotSpot CMS HotSpot CMS сборщиксборщик Сборка молодого поколения копированием Не перемещает объекты в старом поколении Статистические методы борьбы с фрагментацией Две дополнительные STW фазы
initial-mark, remark Вся остальная работа происходит в фоне
Длительность пауз Длительность пауз CMS CMS сборщикасборщика
CMS CMS и фрагментация памятии фрагментация памятиCMS не перемещает объекты в старшем поколении.CMS использует отдельные списки свободного места (FSL) для каждого размера выделяемого блока.
Профилактика фрагментации:• увеличение размера кучи• более частые циклы сборки• HotSpot JVM версии 6u26 и старше
Советы по настройке Советы по настройке CMSCMS
Настройка CMS на большом объёме кучи• -XX:MaxNewSize= ? – размер молодого поколения• -XX:CMSWaitDuration= ? • -XX:-CMSConcurrentMTEnabled – защита от бага в JVM• -XX:+UseCMSInitiatingOccupancyOnly• -XX:+CMSClassUnloadingEnabled – если действительно нужно• -XX:ParGCCardsPerStrideChunk= ? – если куча больше 16 GiB• JVM 1.6u26 или более поздняя• плюс логирование GC
Другие причины паузДругие причины пауз
• Свопинг ОС• Обработка ссылок (weak, soft, phantom, JNI)• Объекты требующие “финализации”• JNI, native код может блокировать GC• Проблемы с permanent generation
HotSpot G1HotSpot G1
G1 (Garbage First) – новый алгоритм в последних версия HotSpot JVM
Решит ли он проблему пауз?
Можно лучше – Можно лучше – OpenJDK OpenJDK патчпатч
http://blog.ragozin.info/2011/07/openjdk-patch-cutting-down-gc-pause.html
RFE-7068625
ИТОГИТОГ: : Сборка мусора в Сборка мусора в JVMJVM Сборка мусора не чёрная магия Каждое приложение индивидуально Приложение не должно мешать сборщику мусора JVM может работать “почти” без пауз
(с паузами не более 100-200ms) Автоматическое управление памятью не
универсально(Проблемные приложения: HBase, Cassandra, …)
АльтернативыАльтернативыjava.nio.ByteBuffer.allocateDirect()Достоиства• Память выделяется вне кучи• Память освобождается автоматически (через ByteBuffer объект)• Кроссплатформенность, “чистая Java”Недостатки• Фрагментация памяти вне кучи• Память освобождается автоматически (через ByteBuffer объект)• Усложняет многопоточное программирование• -XX:MaxDirectMemorySize=<value>
АльтернативыАльтернативы
Real Time System JavaИерархия регионов памяти• Объекты выделяются в выбранном регионе• Локальные и “бессмертные” регионы не собираются• Локальные регионы освобождаются целиком• Глобальные объекты не могу ссылаться на локальные
АльтернативыАльтернативы
Unsafe Java™sun.misc.Unsafe• Unsafe.allocateMemory(…)• Unsafe.reallocateMemory(…)• Unsafe.freeMemory(…)