Подтвердить что ты не робот

Ошибка JVM OutOfMemory "Смертельная спираль" (не утечка памяти)

Недавно мы перенесли ряд приложений из под управлением RedHat linux JDK1.6.0_03 в Solaris 10u8 JDK1.6.0_16 (гораздо более высокие спецификации), и мы заметили, что это довольно сложная проблема: при определенных нагрузках наши JVM попадают в "Спираль смерти" и, в конечном счете, теряют память. Что следует отметить:

  • это не случай утечки памяти. Это приложения, которые работают очень хорошо (в одном случае более 3 лет), а ошибки из-за памяти в любом случае не уверены. Иногда приложения работают, иногда они не
  • это не мы переходим к 64-разрядной VM - мы все еще запускаем 32-битный
  • В одном случае использование последнего сборщика мусора G1 на 1.6.0_18, похоже, решило проблему. В другом, откат назад до 1.6.0_03 работал
  • Иногда наши приложения падают с ошибками HotSpot SIGSEGV
  • Это влияет на приложения, написанные на Java, а также на Scala

Самый важный момент заключается в следующем: поведение проявляется в тех приложениях, которые внезапно получают поток данных (обычно через TCP). Это как если бы VM решает продолжать добавлять больше данных (возможно, переходить к TG), а не запускать GC в "пространстве новостей", пока не поймет, что он должен делать полный GC, а затем, несмотря на то, что практически все на VM является мусором, он как-то решает не собирать его!

Звучит безумно, но я просто не понимаю, что еще. Как еще вы можете объяснить приложение, которое одна минута падает с максимальной кучей 1Gb, а следующая работает просто отлично (никогда не происходит около 256 миллионов, когда приложение делает то же самое)

Итак, мои вопросы:

  • Кто-нибудь еще наблюдал подобное поведение?
  • есть ли какие-либо предложения относительно того, как я могу отлаживать сам JVM (в отличие от моего приложения)? Как доказать, что это проблема с VM?
  • Есть ли там форумы VM-специалиста, где я могу попросить авторов VM (если они не находятся на SO)? (У нас нет контракта на поддержку)
  • Если это ошибка в последних версиях виртуальной машины, почему никто ее не заметил?
4b9b3361

Ответ 1

Интересная проблема. Похоже, что один из сборщиков мусора плохо работает в вашей конкретной ситуации.

Вы пытались изменить используемый сборщик мусора? Есть много вариантов GC, и выяснение, какие из них оптимальны, кажется немного черным искусством, но мне интересно, будет ли для вас базовое изменение.

Я знаю, что есть "серверный" GC, который имеет тенденцию работать намного лучше, чем стандартные. Вы используете это?

Threaded GC (по моему мнению, по умолчанию), вероятно, является наихудшим для вашей конкретной ситуации, я заметил, что он имеет тенденцию быть менее агрессивным, когда машина занята.

Одна вещь, которую я заметил, часто принимает два GC, чтобы убедить Java фактически вынуть мусор. Я думаю, что первый из них имеет тенденцию отсоединять кучу объектов, а второй фактически удаляет их. То, что вы, возможно, захотите сделать, - это иногда заставлять две коллекции мусора. Это приведет к серьезной паузе GC, но я никогда не видел случая, когда потребовалось больше двух, чтобы очистить всю кучу.

Ответ 2

У меня была такая же проблема на машинах Solaris, и я решил ее, уменьшив максимальный размер JVM. Кажется, что 32-битная реализация Solaris нуждается в некоторой служебной комнате за пределами того, что вы выделяете для JVM при сборе сборщиков мусора. Так, например, с -Xmx3580M я получу ошибки, которые вы описываете, но с -Xmx3072M все будет хорошо.

Ответ 3

  • Да, я наблюдал это поведение раньше, и обычно после бесчисленных часов настройки параметров JVM он начинает работать.
  • Сбор мусора, особенно в многопоточных ситуациях, является недетерминированным. Определение ошибки в недетерминированном коде может быть проблемой. Но вы можете попробовать DTrace, если используете Solaris, и есть много вариантов JVM для просмотра в HotSpot.
  • Идите на Scala IRC и посмотрите, висит ли Ismael Juma (ijuma). Он помогал мне раньше, но я думаю, что настоящая глубокая помощь требует оплаты за это.
  • Я думаю, что большинство людей, которые делают такие вещи, соглашаются с тем, что они либо должны быть экспертами по настройке JVM, либо иметь персонал, либо нанять консультанта. Есть люди, которые специализируются на настройке JVM.

Чтобы решить эти проблемы, я считаю, что вам нужно реплицировать их в контролируемой среде, где вы можете точно дублировать прогоны с различными параметрами настройки и/или изменениями кода. Если вы не можете этого сделать, эксперт, вероятно, не сделает вам ничего хорошего, и самый дешевый выход из проблемы - это, вероятно, покупка большего количества оперативной памяти.

Ответ 4

Какого рода OutOfMemoryError вы получаете? Является ли пустое пространство исчерпанным или является проблемой, связанной с любым из других пулов памяти (обычно у ошибки есть сообщение, дающее более подробную информацию о его причине).

Если куча исчерпана и проблема может быть воспроизведена (она звучит так, как если бы она могла), я бы в первую очередь сконфигурировал виртуальную машину для создания кучи кучи на OutOfMemoryErrors. Затем вы можете проанализировать кучу и убедиться, что она не заполнена объектами, которые до сих пор доступны через некоторые неожиданные ссылки.

Конечно, не исключено, что вы работаете с ошибкой VM, но если ваше приложение полагается на конкретное поведение конкретной версии в 1.6.0_03, оно может по какой-то причине оказаться в роли хаоса памяти при работе в версии 1.6. 0_16. Такие проблемы также могут быть обнаружены, если вы используете какой-либо серверный контейнер для своего приложения. Некоторые разработчики, очевидно, не могут читать документацию, но склонны наблюдать за поведением API и делать собственные выводы о том, как что-то должно работать. Это, конечно, не всегда правильно, и я столкнулся с аналогичными проблемами как с Tomcat, так и с JBoss (оба продукта по крайней мере используются для работы только с конкретными виртуальными машинами).

Ответ 5

Также убедитесь, что это не аппаратная ошибка (попробуйте запустить MemTest86 или аналогичный на сервере.)