2010-08-11 3 views
9

Приложение, которое мы недавно начали спорадически сбой, с сообщением о «java.lang.OutOfMemoryError: запрошено 8589934608 байт для Chunk :: new. Из области подкачки?».Java JIT-компилятор, вызывающий OutOfMemoryError

Я посмотрел вокруг на сети, и везде предложения ограничиваются

  • вернуться к предыдущей версии Java
  • скрипки с настройками памяти
  • использование клиента вместо режима сервера

Возвращение к предыдущей версии подразумевает, что у новой Java есть ошибка, но я не видел никаких указаний на это. Память не является проблемой вообще; сервер имеет 32 ГБ, а Xmx установлен на 20, а Xms равно 10. Я не вижу, что JVM заканчивается из оставшихся 12 ГБ (меньше суммы, предоставляемой нескольким другим процессам на машине). И мы застряли в режиме сервера из-за характера приложения и среды.

Когда я смотрю на использование памяти и процессора для приложения, я вижу постоянное использование памяти в течение всего дня, но затем внезапно перед тем, как он умрет, загрузка процессора достигает 100%, а использование памяти идет от X, до X + 2GB, до X + 4GB, до (иногда) X + 8GB, до смерти JVM. Похоже, что в JIT-компиляции происходит цикл повторного изменения размера массива.

Я теперь видел ошибку, связанную с вышеуказанным запросом 8 ГБ, а также запросами 16 ГБ. Все время метод, скомпилированный, когда это происходит, тот же. Это простой метод, который не имеет вложенных циклов, не рекурсии и не использует методы для объектов, которые возвращают статические поля-члены или поля экземпляра непосредственно с небольшим вычислением.

Так что у меня 2 вопроса:

  1. Кто-нибудь есть какие-либо предложения?
  2. Могу ли я проверить, есть ли проблема с компиляцией этого конкретного метода в тестовой среде, без запуска всего приложения, вызывающего JIT-компилятор напрямую? Или я должен запустить приложение и сказать ему, чтобы скомпилировать методы после гораздо меньшего количества вызовов (например, 2), чтобы заставить его скомпилировать метод почти мгновенно, а не в случайную точку дня?

@StephenC

Виртуальная машина Java является 1.6.0_20 (ранее 1.6.0_0), работающий на Solaris. Я знаю, что это компиляция, которая вызывает проблему по нескольким причинам.

  1. ps в секундах, ведущих к нему, показывает, что Java нить с ID, соответствующий компилятор нити (от jstack) принимает до 100% процессорного времени
  2. jstack показывает, проблема заключается в JavaThread "CompilerThread1" daemon [_thread_in_native, id=34, ...]

Метод, упомянутый в jstack, всегда один и тот, который мы написали. Если вы посмотрите на образец jstack, вы поймете, что я имею в виду, но по очевидным причинам я не могу предоставить образцы кода или имена файлов. Я скажу, что это очень простой метод. Essentiall содержит несколько нулевых проверок, 2 для циклов, которые выполняют проверки равенства и, возможно, назначают значения, и некоторые простые вызовы методов после.Всего возможно 40 строк кода.

Эта проблема произошла 2 раза в 2 недели, хотя приложение запускается каждый день и перезапускается ежедневно. Кроме того, приложение не было под большой нагрузкой в ​​любое время.

+0

Было бы полезно, если бы вы сказали, какую версию JVM и уровень патча вы используете (и что это было до этого), и что ваша платформа для ОС/оборудования. Кроме того, почему вы пришли к выводу, что проблема возникает во время компиляции JIT, как вы выяснили метод, который компилируется ... и как выглядит код метода. –

+0

Вы нашли удовлетворительное решение? –

+0

Извините за * очень * поздний ответ - я уже отметил ответ – Phil

ответ

1

Хорошо, я сделал быстрый поиск и нашел тему на солнце java forums that discusses. Надеюсь, поможет.

+0

Да, я тоже это увидел. Его проблема связана с тем, что память остается на одном уровне. Я вижу несколько изменений массива, где их не должно быть. Нет никаких оснований полагать, что для компиляции метода требуется 16 ГБ памяти, верно? – Phil

+0

Тогда вы также, вероятно, попробовали предложения, упомянутые в своем вопросе. Кто-нибудь из них работает? – naikus

1

Здесь еще entry on Oracles forum. Сильный спорадический крах. Существует один ответ, на котором можно решить проблему, переконфигурировав соотношение выживших gc.

5

Вы можете исключить определенный метод из JIT, создав файл с именем .hotspot_compiler и помещая его в рабочий каталог приложений. Просто добавьте запись в файл в следующем формате:

exclude com/amir/SomeClass someMethod 

И выход консоли от компилятора будет выглядеть следующим образом:

### Excluding compile: com.amir.SomeClasst::someMethod 

Для получения более подробной информации читайте this. Если вы не знаете, какой у вас рабочий каталог приложений, используйте

-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler 

в вашем скрипте запуска Java или командной строке.

В качестве альтернативы, если вы не уверены в том, что его компиляторы JIT ошибочны, и вы хотите узнать, можете ли вы воспроизвести проблему без каких-либо JIT'ing, запустите Java-процесс с помощью -Xint.