out of memory error java lang outofmemoryerror как исправить

Какие бывают типы OutOfMemoryError или из каких частей состоит память java процесса

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Область памяти, занимаемая java процессом, состоит из нескольких частей. Тип OutOfMemoryError зависит от того, в какой из них не хватило места.

1. java.lang.OutOfMemoryError: Java heap space

2. java.lang.OutOfMemoryError: PermGen space

3. java.lang.OutOfMemoryError: GC overhead limit exceeded

4. java.lang.OutOfMemoryError: unable to create new native thread

Впервые я столкнулся с данной ошибкой несколько лет назад, когда занимался нагрузочным тестированием и пытался выяснить максимальное количество пользователей, которые могут работать с нашим веб-приложением. Я использовал специальную тулзу, которая позволяла логинить пользователей и эмулировать их стандартные действия. На определенном количестве клиентов, я начал получать OutOfMemoryError. Не особо вчитываясь в текст сообщения и думая, что мне не хватает памяти на создание сессии пользователя и других необходимых объектов, я увеличил размер кучи приложения (-Xmx). Каково же было мое удивление, когда после этого количество пользователей одновременно работающих с системой только уменьшилось. Давайте подробно разберемся как же такое получилось.

На самом деле это очень просто воспроизвести на windows на 32-битной машине, так как там процессу выделяется не больше 2Гб.

Более подробно, что же лежит в стеке потока, и куда уходит эта память, можно прочитать тут.

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

Источник

OutOfMemoryError: поймай, если сможешь

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Всем привет! Сегдня хотел бы поделиться опытом обратоки ошибки ООМ. Эту статью меня побудила написать проблема, с которой я столкнулся. И которая, как позже выяснилось, долгое время оставалсь незамеченой. Меня заинтересовал этот вопрос, так что я решил изучить его немного глубже.

Предистория

У нас есть сервис, который по расписани закидывает задачу по обработке данных в ExecutorService. Это достаточно тяжелая задача. И в один прекрасный момент информации просто стало больше и она не влезла в наш -Xmx.

ООМ своими руками

Для тестирования мне необходимо забить всю память объектами, которые GC будет считать живыми. Для этого я использовал следующий код:

Тут тоже присутствует некоторая проблема, но об этом позже.

Обычный код

Этот код вроде бы выглядит неплохо, ничего особенного тут нет. Наверное, многие писали что-то подобное не один раз. Но проблема в том, что прм ООМ, не будет выведено вообще ничего. Ни в лог ни в поток вывода.

Лови Throwable — говорили они

Да точно, ведь OutOfMemoryError — это Error, а не Exception. Поэтому тут он успешно прлетает мимо catch блока и перехватывается уже в коде ThreadPoolExecutor. Где проглатывается, а сам поток начинает ждать новой задачи. Всем известно, что в самой корневой точке кода лучше ловить Throwable.

К сожалению, если вместо Exception в данной ситуации поймать Throwable, ничего не изменится. При вызове logger.error(), мы просто получим новый ООМ, который так же канет в недрах ThreadPoolExecutor.

Стоит заметить, что если бы вместо ExecutorService создавался бы новый Thread, то все ошибки в конечном счете были бы обработаны UncaughtExceptionHandler в случае смерти потока, и в stderr была бы информация. ThreadPoolExecutor же пытается переиспользовать потоки, что в принципе ожидаемо.

Потерянный OutOfMemoryError

Закидывая задачу в ExecutorService, мы забыли очень важную вещь — воспользоваться Future, который возвращает метод submit().

Теперь стало немного лучше. Если logger.error() выкинет новый ООМ, то main поток свалится и, возможно, выведет ошибку. Это помогает вытащить результат из ExecutorService наружу. Все видели что-то подобное:

Это сообщение выводит обработчик ошибок по умолчанию, который вызывается в случае непредвиденной смерти потока.

UncaughtExceptionHandler — не панацея

Не стоит радоваться раньше вреени, т.к. лучше стало совсем немного. Если не переопределить обработчик, то вызывается ThreadGroup.uncaughtException(), в котором есть следующий код:

Первая же строка создает новый объект при помощи конкатенации и, если там не вылетит новый ООМ, то есть большая вероятность получить его в printStackTrace(). Тут все зависит от обстоятельств. Но суть в том, что даже получив ООМ в главном потоке, есть шанс ничего о нем не узнать.

Финализируй это

Итак, теперь наша проблема в том, что нет памяти для логирования. Из-за чего получаем вторую ошибку. Так может быть попробуем освободить пространство? Проблема заключчается в том, что MemoryGrabber.array — статическая переменная. И объекты доступные через нее GC считает живыми. Попробую ее почистить.

Теперь во время логирования будет вызван сборщик мусора, который уже сможет удалить ненужную структуру данных.

Ода функциональному программированию

Вначале я сказал, что в MemoryGrabber есть проблема. Она заключается в статической переменной array. Дело в том, что эта переменная продолжает жить после того момента, как все свалилось с ошибкой. Очевыдным костылем является ее обнуление в блоке finaly. Было бы намного лучше, если она хранилась на стеке вызова.

Теперь нашь лист List превратится в мусор как только завершится метод grabAllMemory. Не важно, с ошибкой или без. Почти Scala.

Как надо делать

Надеюсь, мне удалось донести мысль о том, что попытки поймать и обработать OutOfMemoryError в коде — сомнительная затея по ряду причин. Для этих целей лучше полагаться на следующие параметры JVM:

Последние два параметра появились только в JDK 8u92, остальные еще в 1.4. Оптимальным поведением является завершение процесса в случае OutOfMemoryError. Такая логика — самая понятная для всех разработчиков и тех, кто будет поддерживать приложение. Попытки обработать подобные ошибки могут привести к последствиям, неочевидным даже для самого автора.

Выводы

В статье я постарался разобраться в некоторых ошибках, из-за которых могут возникнуть проблемы при появлении ООМ. Чтобы их избежать, нужно иметь в виду:

Источник

OutOfMemoryError. Боремся с утечками памяти в Android

Для привлечения внимания к новому функционалу было принято решение воспользоваться анимацией. Необходимо было показать на короткий период View с подсказкой. Пример можно увидеть на изображении ниже:

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Позже обнаружилась утечка Activity.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Проблема заключалась в том, что анимация fadeOut использовала слушателя от анимации fadeIn, что приводило к бесконечному запуску анимации fadeOut.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Исправить это было достаточно легко.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Анимации часто являются причинами утечек. Этого очень легко достигнуть забыв остановить бесконечную анимацию или запустив анимацию на неоправданно длительное время.

android.widget.Editor$Blink

Бывает утечки памяти находятся и в самой платформе. Однажды я получил такой отчет:

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Чтобы воспроизвести утечку достаточно создать Dialog с EditText внутри и что-нибудь в нем напечатать.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Как оказалось, это известный баг и он уже исправлен. Там же можно найти хак, для исправления этой утечки:

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Утечка от производителя. Singleton — зло

В одном из отчетов я получил утечку с не публичным, неизвестным мне ранее классом. Оказалось, что это приватный класс от одного популярного производителя.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

На этот раз мне опять повезло и я нашел готовое решение в сети (1, 2).

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Результаты

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

В результате количество OutOfMemoryError уменьшилось почти в 7 раз. Так же уменьшилось количество RuntimeException,InflateException: часть из них — это пойманные и обернутые OutOfMemoryError. Одним из ограничивающих факторов в исправлении такого рода ошибок является то, что я не могу делать обновления, которые не содержат внешних изменений (для пользователей выглядит как “Пустое обновление”) В таких случаях приходится ждать реализации нового функционала для проверки результатов.

Источник

Многие пользователи ПК во время работы с какой-либо программой могут столкнуться с «вылетом» указанной программы, и появившимся сообщением «Out of memory». Возникшая проблема может иметь множество причин, начиная от банального недостатка памяти на пользовательском ПК, и заканчивая некорректной работой с памятью какой-либо программы.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Причины появления дисфункции

Сообщение «Out of memory» (в переводе дословно «вне памяти», или «недостаточно памяти») обычно возникает при недостатке памяти на пользовательском компьютере. В частности же, в появлении данной ошибки «виновен» следующий набор факторов:

Когда вашему компьютеру не хватает физической R.A.M. памяти, он заимствует часть места на жёстком диске, и создаёт так называемую «виртуальную память». Система временно хранит в такой виртуальной памяти ту часть данных, которая не помещается в памяти обычной. Такие данные обычно хранятся в файле «pagefile.sys», размер которого может увеличиваться или уменьшаться в зависимости от специфики работы вашей ОС. Если на диске будет недостаточно места, файл «pagefile.sys» не сможет расти, и пользователь получит рассматриваемую ошибку.

Как исправить ошибку «Out of memory»

Для решения указанной проблемы рекомендую сделать следующее:

Альтернативным вариантом решения проблемы является установка соответствующего фикса от Майкрософт. Или использование расширений или дополнений для браузера уровня «The Great Suspender» для «Google Chrome», хорошо работающего с ненужными вкладками браузера.

bcdedit/set IncreaseUserVa 3072

И нажмите на ввод, и перезагрузите ваш ПК. Функционал данной команды позволяет выделить пользовательским приложениям 3 гигабайта оперативной памяти для работы. В некоторых системах этого может быть слишком много, потому если после ввода данной команды система начала чаще сбоить, то введите в командной строке от имени администратора:

bcdedit /set IncreaseUserVa 2560 — что позволит задействовать 2,5 гигабайта вместо ранее забронированных 3.

Если ситуацию этим исправить не удалось, верните настройки на состояние по умолчанию:

bcdedit /deletevalue IncreaseUserVa

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Установите нужный размер файла подкачки

Заключение

Ошибка «Out of memory» может иметь множество причин, связанных как с физическим недостатком памяти на ПК, так и другими детерминантами, изложенными мной выше. Для решения проблемы советую закрыть ненужные программы (вкладки браузера) на вашем компьютере (тем самым разгрузив его память), а самым эффективным инструментом является установка дополнительной планки памяти на ПК, что в большинстве случаев поможет избавиться от ошибки на вашем компьютере.

Источник

Как бороться с OutOfMemoryError на практике, или ох уж мне эти базы данных

Предыстория

Для начала нужно понять, как возникает OOM. Кому-то это может быть ещё неизвестно.
Представьте себе, что есть какой-то верхний предел занимаемой оперативки для приложения. Пусть это будет гигабайт ОЗУ.
Само по себе возникновение OOM в каком-то из потоков ещё не означает, что именно этот поток «выжрал» всю свободную память, да и вообще не означает, что именно тот кусок кода, который привёл к OOM, виноват в этом.
Вполне нормальна ситуация, когда какой-то поток чем-то занимался, поедая память, «дозанимался» этим до состояния «ещё немного, и я лопну», и завершил выполнение, приостановившись. А в это время какой-то другой поток решил запросить для своей маленькой работы ещё немного памяти, сборщик мусора попыжылся, конечно, но мусора уже в памяти не нашёл. В этом случае как раз и возникает OOM, не связанный с источником проблемы, когда стектрейс покажет совсем не того виновника падения приложения.

Есть и другой вариант. Около недели я исследовал, как улучшить жизнь парочки наших приложений, чтобы они перестали себя нестабильно вести. И ещё недельку-две потратил на то, чтобы привести их в порядок. В общей сложности пара недель времени, которые растянулись на полтора месяца, ведь занимался я не только этими проблемами.
Из найденного: сторонняя библиотека, и, конечно же, некоторые неучтённые вещи в вызовах хранимых процедур.
В одном приложении симптомы были следующие: в зависимости от нагрузки на сервис, оно могло упасть через сутки, а могло через двое. Если помониторить состояние памяти, то было видно, что приложение постепенно набирало «размер», и в определённый момент просто ложилось.
С другим приложением несколько интереснее. Оно может вести себя хорошо длительный срок, а могло перестать отвечать минут через 10 после перезагрузки, или вдруг внезапно упасть, сожрав всю свободную память (это я уже сейчас вижу, наблюдая за ним). А после обновления версии, когда была изменена и версия Tomcat с 7й до 8й, и JRE, оно вдруг в одну из пятниц (проработав вменяемо до этого ни много ни мало — 2 недели) начало творить такие вещи, что стыдно признаваться в этом. 🙂

В обоих историях очень полезны оказались дампы, благодаря им удалось отыскать все причины падений, подружившись с такими инструментами, как JVisualVM (буду называть его JVVM), Eclipse Memory Analyzing Tool (MAT) и языком OQL (может быть я не умею его правильно готовить в MAT, но мне оказалось легче подружиться с реализацией OQL именно в JVVM).
Ещё вам понадобится свободная оперативка для того, чтобы было куда загружать дампы. Её объём должен быть соизмерим с размером открываемого дампа.

Начало

Итак, начну потихоньку раскрывать карты, и начну именно с JVVM.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Этот инструмент в соединении с jstatd и jmx позволяет удалённо наблюдать за жизнью приложения на сервере: Heap, процессор, PermGen, количество потоков и классов, активность потоков, позволяет проводить профилирование.
Также JVVM расширяем, и я не преминул воспользоваться этой возможностью, установив некоторые плагины, которые позволили куда больше вещей, например, следить и взаимодействать с MBean’ами, наблюдать за деталями хипа, вести длительное наблюдение за приложением, держа в «голове» куда больший период метрик, чем предоставляемый вкладкой Monitor час.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Вот так выглядит набор установленных плагинов.
Visual GC (VGC) позволяет видеть метрики, связанные с хипом.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Вот два скриншота вкладки VGC, которые показывают, как ведут себя два разных приложения.
Слева Вы можете увидеть такие разделы хипа, как Perm Gen, Old Gen, Survivor 0, Survivor 1, и Eden Space.
Все эти составляющие — участки в оперативке, в которую и складываются объекты.
PermGen — Permanent Generation — область памяти в JVM, предназначенная для хранения описания классов Java и некоторых дополнительных данных.
Old Gen — это область памяти для достаточно старых объектов, которые пережили несколько перекладываний с места на место в Survivor-областях, и в момент какого-то очередного переливания попадают в область «старых» объектов.
Survivor 0 и 1 — это области, в которые попадают объекты, которые после создания объекта в Eden Space пережили его чистку, то есть не стали мусором на момент, когда Eden Space начал чиститься Garbage Collector’ом (GC). При каждом запуске чистки Eden Space объекты из активного в текущий момент Survivor’а перекладываются в пассивный, плюс добавляются новые, и после этого Survivor’ы меняются статусами, пассивный становится активным, а активный — пассивным.
Eden Space — область памяти, в которой новые объекты порождаются. При нехватке памяти в этой области запускается цикл GC.

Перейдём ко второму приложению:
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
В нём Eden напоминает мне какой-то уровень из Mortal Kombat, арену с шипами. Была такая, кажется… А График GC — шипы из NFS Hot Pursuit, вот те вот, плоские ещё.
Числа справа от названий областей указывают:
1) что Eden имеет размер в 50 мегабайт, и то, что нарисовано в конце графика, последнее из значений на текущий момент — занято 25 мегабайт. Всего он может вырости до 546 мегабайт.
2) что Old может вырости до 1,333 гига, сейчас занимает 405 МБ, и забит на 145,5 МБ.
Так же для Survivor-областей и Perm Gen.
Для сравнения — вот Вам Tracer-график за 75 часов работы второго приложения, думаю, кое-какие выводы вы сможете сделать из него. Например, что активная фаза у этого приложения — с 8:30 до 17:30 в рабочие дни, и что даже на выходных оно тоже работает 🙂
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Если вы вдруг увидели в своём приложении, что Old-область заполнена — попробуйте просто подождать, когда она переполнится, скорее всего она заполнена уже мусором.

Мусор — это объекты, на которые нет активных ссылок из других объектов, или целые комплексы таких объектов (например, какое-то «облако» взаимосвязанных оъектов может стать мусором, если набор ссылок указывает только на объекты внутри этого «облака», и ни на один объект в этом «облаке» ничто не ссылается «снаружи»).

Это был краткий пересказ того, что я узнал про структуру хипа за время, пока гуглил.

Предпосылки

Итак, случилось сразу две вещи:
1) после перехода на более новые библиотеки/томкеты/джавы в одну из пятниц приложение, которое я уже долгое время веду, вдруг стало вести себя из рук вон плохо спустя две недели после выставления.
2) мне на рефакторинг отдали проект, который тоже вёл себя до некоторого времени не очень хорошо.

Я уже не помню, в каком точно порядке произошли эти события, но после «чёрной пятницы» я решил наконец-то разобраться с дампами памяти детальнее, чтобы это более не было для меня чёрным ящиком. Предупреждаю, что какие-то детали я мог уже запамятовать.

По первому случаю симптомы были такие: все потоки, отвественные за обработку запросов, выжраны, на базу данных открыто всего 11 соединений, и те не сказать, что используются, база говорила, что они в состоянии recv sleep, то есть ожидают, когда же их начнут использовать.
После перезагрузки приложение оживало, но прожить могло недолго, вечером той же пятницы жило дольше всего, но уже после окончания рабочего дня таки снова свалилось. Картина всегда была одинаковой: 11 соединений к базе, и лишь один, вроде бы, что-то делает.
Память, кстати, была на минимуме. Сказать, что OOM привёл меня к поиску причин, не могу, однако полученные знания при поиске причин позволили начать активную борьбу с OOM.

Когда я открыл дамп в JVVM, из него было сложно что-либо понять.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Подсознание подсказывало, что причина где-то в работе с базой.
Поиск среди классов сказал мне, что в памяти аж 29 DataSource, хотя должно быть всего 7.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Это и дало мне точку, от которой можно было бы оттолкнуться, начать распутывать клубок.

Сидеть переклацывать в просмотровщике все эти объекты было некогда, и моё внимание наконец-то привлекла вкладка OQL Console, я подумал, что вот он, момент истины — я или начну использовать её на полную катушку, или так и забью на всё это.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить

Прежде, чем начать, конечно же был задан вопрос гуглу, и он любезно предоставил шпаргалку (cheat sheet) по использованию OQL в JVVM: http://visualvm.java.net/oqlhelp.html

Сначала обилие сжатой информации привело меня в уныние, но после применения гугл-фу на свет таки появился вот такой OQL-запрос:

Это уже исправленная и дополненная, финальная версия этого запроса 🙂
Результат можно увидеть на скриншоте:
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
После нажатия на BasicDataSource#7 мы попадаем на нужный объект во вкладке Instances:
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Через некоторое время до меня дошло, что есть одно несхождение с конфигурацией, указанной в теге Resource в томкете, в файле /conf/context.xml. Ведь в дампе параметр maxTotal имеет значение 8, в то время, как мы указывали maxActive равным 20…
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Тут-то до меня и начало доходить, что приложение жило с неправильной конфигурацией пула соединений все эти две недели!
Для краткости напишу тут, что в случае, если вы используете Tomcat и в качестве пула соединений — DBCP, то в 7м томкете используется DBCP версии 1.4, а в 8м томкете — уже DBCP 2.0, в котором, как я потом выяснил, решили переименовать некоторые параметры! А про maxTotal вообще на главной странице сайта написано 🙂
http://commons.apache.org/proper/commons-dbcp/
«Users should also be aware that some configuration options (e.g. maxActive to maxTotal) have been renamed to align them with the new names used by Commons Pool 2.»

Причины

Обозвал их по всякому, успокоился, и решил разобраться.
Как оказалось, класс BasicDataSourceFactory просто напросто получает этот самый Resource, смотрит, есть ли нужные ему параметры, и забирает их в порождаемый объект BasicDataSource, молча игнорируя напрочь всё, что его не интересует.
Так и получилось, что они переименовали самые весёлые параметры, maxActive => maxTotal, maxWait => maxWaitMillis, removeAbandoned => removeAbandonedOnBorrow & removeAbandonedOnMaintenance.
По умолчанию maxTotal, как и ранее, равен 8; removeAbandonedOnBorrow, removeAbandonedOnMaintenance = false, maxWaitMillis устанавливается в значение «ждать вечно».
Получилось, что пул оказался сконфигурирован с минимальным количеством соединений; в случае, если заканчиваются свободные соединения — приложение молча ждёт, когда они освободятся; и добивает всё молчанка в логах по поводу «заброшенных» соединений — то, что могло бы сразу показать, в каком именно месте программист мудак код хватает соединение, но не отдаёт его обратно по окончанию своей работы.
Это сейчас вся мозаика сложилась быстро, а добывались эти знания дольше.

«Так быть не должно», решил я, и запилил патчик (https://issues.apache.org/jira/browse/DBCP-435, выразился в http://svn.apache.org/viewvc/commons/proper/dbcp/tags/DBCP_2_1/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java?view=markup ), патч был принят и вошёл в версию DBCP 2.1. Когда и если Tomcat 8 обновит версию DBCP до 2.1+, думаю, что админам откроются многие тайны про их конфигурации Resource 🙂

По поводу этого происшествия мне лишь осталось рассказать ещё одну деталь — какого чёрта в дампе было аж 29 DataSource’ов вместо всего 7 штук. Разгадка кроется в банальной арифметике, 7*4=28 +1=29.

На каждую подпапку внутри папки /webapps поднимается своя копия /conf/context.xml, а значит то количество Resource, которые там есть, следует умножать на количество приложений, чтобы получить общее количество пулов, поднятых в памяти томкета. На вопрос «что в этом случае делать?» ответ будет таким: нужно вынести все объявления Resource из /conf/context.xml в файл /conf/server.xml, внутрь тега GlobalNamingResources. Там Вы можете найти один, имеющийся по умолчанию, Resource name=«UserDatabase», вот под ним и размещайте свои пулы. Далее необходимо воспользоваться тегом ResourceLink, его желательно поместить в приложение, в проекте, внутрь файла /META-INF/context.xml — это так называемый «per-app context», то есть контекст, который содержит объявления компонентов, которые будут доступны только для разворачиваемого приложения. У ResourceLink параметры name и global могут содержать одинаковые значения.
Для примера:

После этого всё стало ясно: 11 соединений было потому, что в одном, активном DataSource было съедено 8 соединений (maxTotal = 8), и ещё по minIdle=1 в трёх других неиспользуемых DataSource-копиях.

В ту пятницу мы откатились на Tomcat 7, который лежал рядышком, и ждал, когда от него избавятся, это дало время спокойно во всём разобраться.
Плюс позже, уже на TC7, обнаружилась утечка соединений, всё благодаря removeAbandoned+logAbandoned. DBCP радостно сообщил в логфайл catalina.log о том, что

Вот этот вот плохойПлохойМетод имеет в сигнатуре Connection con, но внутри была конструкция «con = getConnection();», которая и стала камнем преткновения. СуперКласс вызывается редко, поэтому на него и не обращали внимания так долго. Плюс к этому, вызовы происходили, я так понимаю, не во время рабочего дня, так что даже если что-то и подвисало, то никому уже не было дела до этого. А в ТуСамуюПятницу просто звёзды сошлись, начальнику департамента заказчика понадобилось посмотреть кое-что 🙂

Приложение №2

Что же касается «события №2» — мне отдали приложение на рефакторинг, и оно на серверах тут же вздумало упасть.
Дампы попали уже ко мне, и я решил попробовать поковырять и их тоже.
Открыл дамп в JVVM, и «чё-то приуныл»:
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Что можно понять из Object[], да ещё и в таком количестве?
( Опытный человек, конечно же, увидел уже причину, правда? 🙂 )

Так у меня зародилась мысль «ну неужели никто ранее не занимался этим, ведь наверняка уже есть готовый инструмент!». Так я наткнулся на этот вопрос на StackOverflow: http://stackoverflow.com/questions/2064427/recommendations-for-a-heap-analysis-tool-for-java.
Посмотрев предложенные варианты, я решил остановиться на MAT, надо было попробовать хоть что-то, а это открытый проект, да ещё и с куда бОльшим количеством голосов, чем у остальных пунктов.

Eclipse Memory Analyzing Tool

Итак, MAT.
Рекомендую скачивать последнюю версию Eclipse, и устанавливать MAT туда, потому как самостоятельная версия MAT ведёт себя плохо, там какая-то чертовщина с диалогами, в них не видно содержимого в полях. Быть может кто-то подскажет в комментариях, чего ему не хватает, но я решил проблему, установив MAT в Eclipse.

Открыв дамп в MAT я запросил выполнение Leak Suspects Report.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Удивлению не было предела, честно говоря.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
1.2 гига весят соединения в базу.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Каждое соединение весит от 17 до 81 мегабайта.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Ну и ещё «немного» сам пул.
Визуализировать проблему помог отчёт Dominator Tree:
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Причиной всех падений оказались километры SQLWarning’ов, база настойчиво пыталась дать понять, что «010SK: Database cannot set connection option SET_READONLY_TRUE.», а пул соединений BoneCP не вычищает SQLWarning’и после освобождения и возврата соединений в пул (может быть это где-то можно сконфигурировать? Подскажите, если кто знает).
Гугл сказал, что такая проблема с Sybase ASE известна ещё с 2004 года: https://forum.hibernate.org/viewtopic.php?f=1&t=932731
Если вкратце, то «Sybase ASE doesn’t require any optimizations, therefore setReadOnly() produces a SQLWarning.», и указанные решения всё ещё работают.
Однако это не совсем решение проблемы, потому как решение проблемы — это когда при возврате соединения в пул все уведомления базы очищаются в силу того, что они уже никогда никому не понадобятся.
И DBCP таки умеет делать это: http://svn.apache.org/viewvc/commons/proper/dbcp/tags/DBCP_1_4/src/java/org/apache/commons/dbcp/PoolableConnectionFactory.java?view=markup, метод passivateObject(Object obj), в строке 687 можно увидеть conn.clearWarnings();, этот вызов и спасает от километров SQLWarning’ов в памяти.
Об этом я узнал из тикета: https://issues.apache.org/jira/browse/DBCP-102
Также мне подсказали про вот такой тикет в багтрекере: https://issues.apache.org/jira/browse/DBCP-234, но он касается уже версии DBCP 2.0.

В итоге я перевёл приложение на DBCP (пусть и версии 1.4). Пусть нагрузка на сервис и немаленькая (от 800 до 2к запросов в минуту), но всё же приложение ведёт себя хорошо, а это главное. И правильно сделал, потому как BoneCP уже пять месяцев не поддерживается, правда, ему на смену пришёл HikariCP. Нужно будет посмотреть, как дела в его исходниках…

Сражаемся с OOM

Впечатлившись тем, как MAT мне всё разложил по полочкам, я решил не забрасывать этот действенный инструмент, и позже он мне пригодился, потому как в первом приложении ещё остались всяческие «неучтёнки» — неучтённые вещи в коде приложения или коде хранимых процедур, которые иногда приводят к тому, что приложение склеивает ласты. Я их отлавливаю до сих пор.

Вооружившись обоими инструментами, я принялся ковырять каждый присланный дамп в поисках причин падения по OOM.
Как правило все OOM приводили меня к TaskThread.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
И если нажать на надпись See stacktrace, то да, это будет как раз банальный случай, когда какой-то поток вдруг внезапно упал при попытке отмаршалить результат своей работы.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Однако здесь ничто не указывает на причину возникновения OOM, здесь лишь результат. Найти причину мне пока-что, в силу незнания всей магии OQL в MAT, помогает именно JVVM.
Загружаем дамп там, и пытаемся отыскать причину!
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Искать мне следует, конечно же, именно вещи, связанные с базой данных, а посему попробуем сначала посмотреть, есть ли в памяти Statement’ы.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Два SybCallableStatement, и один SybPreparedStatement.
Думаю, что дело усложнится, если Statement’ов будет куда больше, но немного подрихтовав один из следующих запросов, указав в where нужные условия, думаю, всё у Вас получится. Плюс, конечно же, стоит хорошенько посмотреть в MAT, что за результаты пытается отмаршалить поток, какой объект, и станет понятнее, какой именно из Statement’ов необходимо искать.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Не то, это «внутренние» вызовы.

out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
А вот и дичь!
Для чистоты эксперимента можно кинуть такой же запрос в любимой БД-IDE, и он будет очень долго отрабатывать, а если покопаться в недрах хранимки, то будет понятно, что там просто из базы, которая нам не принадлежит, выбирается 2 миллиона строк по такому запросу с такими параметрами. Эти два миллиона даже влазят в память приложения, но вот попытка отмаршалить результат становится фатальной для приложения. Такое себе харакири. 🙂
При этом GC старательно убирает все улики, но не спасло его это, всё же источник остался в памяти, и он будет наказан.

Почему-то после всего этого рассказа почувствовал себя тем ещё неудачником.

Прощание

Вот и закончилось моё повествование, надеюсь, Вам понравилось 🙂
Хотел бы выразить благодарность своему начальнику, он дал мне время во всём этом разобраться. Считаю эти новые знания очень полезными.
Спасибо девушкам из Scorini за неизменно вкусный кофе, но они не прочтут этих слов благодарности — я даже сомневаюсь, что они знают о существовании Хабрахабра 🙂
Хотелось бы увидеть в комментариях ещё больше полезной инфы и дополнений, буду очень благодарен.

Думаю, самое время почитать документацию к MAT…

UPD2 (2015-10-28) | Случай номер два три
(Было принято решение дописать это сюда как апдейт, а не пилить новую статью о том же самом):
Ещё один интересный случай, но уже с Оракловой базой.
Один из проектов использует фичу с XML, проводит поиски по содержимому сохранённого XML-документа. В общем, этот проект иногда давал о себе знать тем, что вдруг внезапно один из инстансов переставал подавать признаки жизни.
Почуяв «хороший» случай потренироваться на кошках, я решил посмотреть его дампы памяти.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Первое, что я увидел, было «у вас тут много коннектов в памяти осталось». 21к. И какой-то интересный oracle.xdb.XMLType тоже давал жару. «Но это же Оракл!», вертелось у меня в голове. Забегая вперёд скажу что таки да, он виноват.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Итак, видим кучу T4CConnection, которые лежат в HashMap$Entry. Обратил внимание сразу, что вроде бы и SoftHashMap, что, вроде как, должно означать, что оно не должно вырастать до таких размеров. Но результат видите и сами — 50-60 килобайт в коннекте, и их реально МНОГО.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Посмотрев, что собой представляют HashMap$Entry — увидел, что примерно картина одинакова, всё связано с SoftHashMap, с Оракловыми коннектами.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
Что, собственно, подтверждалось такой картинкой. HashMap$Entry было просто море, и они более-менее сакуммулировались внутри oracle.xdb.SoftHashMap.
В следующем дампе картина была примерно такой же. По Dominator Tree было видно, что внутри каждого Entry находится тяжёлый такой BinXmlProcessorImpl.
out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить out of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправитьout of memory error java lang outofmemoryerror как исправить. Смотреть фото out of memory error java lang outofmemoryerror как исправить. Смотреть картинку out of memory error java lang outofmemoryerror как исправить. Картинка про out of memory error java lang outofmemoryerror как исправить. Фото out of memory error java lang outofmemoryerror как исправить
-=-=-
Если учесть, что я в тот момент был не силён в том, что такое xdb, и как он связан с XML, то, несколько растерявшись, я решил, что надо бы погуглить, быть может кто-то уже в курсе, что со всем этим нужно делать. И чутьё не обмануло, по запросу «oracle.xdb.SoftHashMap T4CConnection» нашлось
раз piotr.bzdyl.net/2014/07/memory-leak-in-oracle-softhashmap.html
и два leakfromjavaheap.blogspot.com/2014/02/memory-leak-detection-in-real-life.html
Утвердившись, что тут всё-таки косяк у Оракла, дело оставалось за малым.
Попросил администратора БД посмотреть информацию по обнаруженной проблеме:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *