Ошибка OutOfMemory JVM "спираль смерти" (не утечка памяти)
Недавно мы перенесли ряд приложений из RedHat linux JDK1.6.0_03 в Solaris 10u8 JDK1.6.0_16 (машины с более высокой спецификацией) и заметили, что кажется довольно актуальной проблемой: при определенных нагрузках наши JVM получают сами в "Спираль Смерти" и в конце концов выйдут из памяти. Что следует отметить:
- это не случай утечки памяти. Это приложения, которые работали очень хорошо (в одном случае более 3 лет), и ошибки нехватки памяти не гарантированы в любом случае. Иногда приложения работают, иногда нет
- мы не переходим на 64-битную виртуальную машину - мы все еще работаем с 32-битной
- В одном случае использование последней сборки мусора G1 на 1.6.0_18, похоже, решило проблему. В другом переход на 1.6.0_03 сработал
- Иногда наши приложения падают с HotSpot
SIGSEGV
ошибки - Это влияет на приложения, написанные на Java, а также Scala
Наиболее важный момент заключается в следующем: поведение проявляется в тех приложениях, которые внезапно получают поток данных (обычно через TCP). Это как если бы виртуальная машина решила добавлять больше данных (возможно, прогрессируя их в TG), а не запускать GC в "газетах", пока не осознает, что должна выполнить полный GC, а затем, несмотря на то, что практически все в VM является мусором, он как-то решает не собирать его!
Звучит безумно, но я просто не вижу, что это еще. Как еще можно объяснить приложению, у которого одна минута падает с максимальной кучей в 1 Гб, а следующая работает просто отлично (никогда не бывает около 256 Мб, когда приложение делает то же самое)
Итак, мои вопросы:
- Кто-нибудь еще наблюдал такое поведение?
- кто-нибудь есть какие-либо предложения относительно того, как я мог бы отладить сам JVM (в отличие от моего приложения)? Как мне доказать, что это проблема с ВМ?
- Существуют ли форумы для специалистов по ВМ, где я могу задать вопрос авторам ВМ (при условии, что они не на SO)? (У нас нет контракта на поддержку)
- Если это ошибка в последних версиях виртуальной машины, почему никто не заметил этого?
6 ответов
Интересная проблема. Похоже, один из сборщиков мусора плохо работает в вашей конкретной ситуации.
Вы пытались изменить используемый сборщик мусора? Есть много вариантов GC, и выяснение того, какие из них являются оптимальными, кажется черным искусством, но мне интересно, сработают ли основные изменения для вас.
Я знаю, что есть GC "Сервер", который работает намного лучше, чем стандартные. Вы используете это?
Резьбовой GC (который я считаю по умолчанию), вероятно, является худшим для вашей конкретной ситуации, я заметил, что он обычно менее агрессивен, когда машина занята.
Одна вещь, которую я заметил, часто требуется два сборщика мусора, чтобы убедить Java действительно вынести мусор. Я думаю, что первый имеет тенденцию разъединять кучу объектов, а второй фактически удаляет их. То, что вы, возможно, захотите сделать, - это вызвать две сборки мусора. Это вызовет значительную паузу в GC, но я никогда не видел случая, чтобы для очистки всей кучи потребовалось более двух.
У меня была такая же проблема на машинах Solaris, и я решил ее, уменьшив максимальный размер JVM. 32-битная реализация Solaris, очевидно, нуждается в некотором дополнительном пространстве, помимо того, которое вы выделяете для JVM при выполнении сборки мусора. Так, например, с -Xmx3580M
Я получу ошибки, которые вы описываете, но с -Xmx3072M
было бы хорошо.
- Да, я наблюдал такое поведение раньше, и обычно после бесчисленных часов настройки параметров JVM он начинает работать.
- Сборка мусора, особенно в многопоточных ситуациях, является недетерминированной. Определение ошибки в недетерминированном коде может быть проблемой. Но вы можете попробовать DTrace, если вы используете Solaris, и существует множество опций JVM для пиринга в HotSpot.
- Идите на Scala IRC и посмотрите, не торчит ли Исмаэль Джума (иджума). Он помог мне раньше, но я думаю, что настоящая всесторонняя помощь требует оплаты за это.
- Я думаю, что большинство людей, занимающихся подобными вещами, признают, что им либо нужно быть экспертами по настройке JVM, либо иметь одного из них, либо нанять консультанта. Есть люди, которые специализируются на настройке JVM.
Чтобы решить эти проблемы, я думаю, вам нужно иметь возможность реплицировать их в контролируемой среде, где вы можете точно дублировать прогоны с различными параметрами настройки и / или изменениями кода. Если вы не можете этого сделать, найм эксперта, вероятно, не принесет вам пользы, и самый дешевый выход из этой проблемы, вероятно, заключается в покупке большего количества оперативной памяти.
С какими именно ошибками SIGSEV вы сталкиваетесь?
Если вы используете 32-битную виртуальную машину, это может быть то, что я описал здесь: http://janvanbesien.blogspot.com/2009/08/mysterious-jvm-crashes-explained.html
Также убедитесь, что это не аппаратная ошибка (попробуйте запустить MemTest86 или аналогичный на сервере.)
Какой вид OutOfMemoryError вы получаете? Исчерпано ли пространство кучи или проблема связана с каким-либо другим пулом памяти (обычно в сообщении об ошибке содержится более подробная информация о ее причине).
Если куча исчерпана и проблема может быть воспроизведена (это звучит так, как будто она может), я бы прежде всего настроил виртуальную машину на создание дампа кучи на OutOfMemoryErrors. Затем вы можете проанализировать кучу и убедиться, что она не заполнена объектами, которые все еще доступны через некоторые неожиданные ссылки.
Конечно, не исключено, что вы сталкиваетесь с ошибкой виртуальной машины, но если ваше приложение полагается на поведение, специфичное для реализации в 1.6.0_03, оно может по тем или иным причинам закончиться скачком памяти при работе на 1.6.0_16. Такие проблемы также могут быть обнаружены, если вы используете какой-либо серверный контейнер для своего приложения. Некоторые разработчики, очевидно, не могут читать документацию, но, как правило, наблюдают за поведением API и делают собственные выводы о том, как что-то должно работать. Это, конечно, не всегда правильно, и я столкнулся с похожими проблемами как с Tomcat, так и с JBoss (оба продукта, по крайней мере, раньше работали только с конкретными виртуальными машинами).