В последнее время некоторые из наших серверов выходят из строя из-за ошибок. Хотя у меня нет доказанной основной причины, у меня есть догадка, что это связано с тем, как наше приложение собирает мусор, настройкой GC, которую мы сделали, и профилем памяти.
При расследовании нескольких случаев этих сбоев существует шаблон, который я определил с точки зрения JVM:
- до сбоя количество потоков увеличивается до уровня выше нормального
- перед сбоем обычно нормальный шаблон пилообразного общего использования кучи исчезает, и размер кучи увеличивается без уменьшения
- до крушения, молодое поколение кучи неизменно низкое и, похоже, не меняет или не увеличивает в использовании
- до крушения, старое поколение вырастает до размеров, превышающих размеры предыдущих поколений, и, похоже, не очищается и не собирается
- segfault всегда имеет отношение к активному потоку GC, в частности
copy_to_survivor_space
Хотя я не вижу убедительных доказательств возникновения нехватки памяти, я придерживаюсь мнения, что у нас действительно заканчивается свободное пространство для приложения. Если G1GC не может скопировать молодые объекты в оставшееся место до эвакуации или продвижения по службе, кажется, логически следует, что у него не было достаточно места для этого. Анализируя журналы GC, я не вижу ничего общего с огромными объектами, так как не думаю, что они занимают кучу места в куче.
Глядя на профиль памяти, я догадываюсь, что мне нужно уменьшить InitiatingHeapOccupancyPercent
до значения, близкого к значению по умолчанию 45, чтобы запустить цикл сбора данных раньше. Мне кажется, особенно учитывая постоянно растущий размер Old Gen, что смешанный / полный GC должен запускаться чаще или, по крайней мере, раньше. Как начать полную / смешанную коллекцию?
Исходя из предоставленной информации, есть ли другие мысли или мнения о том, как я могу быстрее начать сбор? Я неверно истолковываю сообщение segfault и иду по неверному пути? Что еще я могу сделать, чтобы собрать информацию, которая может помочь мне устранить первопричину сбоев?
Detail
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f38aa2655f5, pid=6293, tid=0x00007f3894efe700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_162-b12) (build 1.8.0_162-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.162-b12 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# V [libjvm.so+0x5c85f5] G1ParScanThreadState::copy_to_survivor_space(InCSetState, oopDesc*, markOopDesc*)+0x45
#
Параметры JVM:
-XX:MaxHeapSize=30g
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=70
-XX:-OmitStackTraceInFastThrow
-XX:+AlwaysPreTouch
-XX:+UseStringDeduplication
-XX:+UseCompressedOops
-Xloggc:/usr/local/company/logs/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=100M
-XX:+PrintAdaptiveSizePolicy
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCCause
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+PrintReferenceGC
-XX:+PrintTenuringDistribution
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/company/logs/heapdump_126960.hprof