код ошибки out of memory chrome
Код ошибки out of memory браузер chrome
11 лучших способов исправить ошибку Google Chrome из-за нехватки памяти в Windows 10
Google Chrome может широко использоваться моими миллиардами по всему миру, но он посмертно печально известен тем, что потребляет ресурсы. Люди, использующие его на старом оборудовании, часто заявляют, что он тормозит, а иногда выдает код ошибки. Многие Пользователи Chrome сообщают о ошибка “нехватки памяти” при недавней загрузке веб-сайта.
На самом деле есть два кода ошибок, с которыми пользователи приветствуют во время просмотра. Один говорит: «Ой, хватка! Что-то пошло не так при отображении этой веб-страницы. Код ошибки: Недостаточно памяти. И другое сообщение об ошибке, которое вы, возможно, просматриваете, говорит: «Ой, щелчок! В Google Chrome не хватило памяти при попытке отобразить эту веб-страницу ».
Оба кода ошибки означают одно и то же. Этому браузеру Chrome не хватает памяти или ресурсов для получения и открытия соответствующей веб-страницы. Для этого может быть несколько причин, которые мы рассмотрим ниже с решениями.
1. Закройте некоторые вкладки.
Открытие слишком большого количества вкладок в Chrome может замедлить работу в Интернете. Проверьте, можете ли вы закрыть некоторые вкладки, которые больше не нужны. Это должно освободить память для других вкладок, а также для новых вкладок.
Также рекомендуется использовать несколько окон Chrome для открытия вкладок. Например, вместо того, чтобы открывать 10 вкладок в одном окне, вы можете открывать 4-5 вкладок в одном, а остальные – в другом окне Chrome. Короче говоря, по возможности управляйте открытыми вкладками, чтобы сэкономить память.
2. Попробуйте режим инкогнито.
Мы рекомендуем использовать режим инкогнито (нажмите Ctrl + Shift + N, чтобы открыть), потому что он отключает все расширения, работающие в фоновом режиме. Иногда расширение может вызывать конфликт.
Откройте веб-страницу, которая выдает ошибку «недостаточно памяти», и проверьте, загружается ли она в режиме инкогнито. Если да, то может быть виновато одно из расширений. Отключите все расширения и включите их по одному, чтобы узнать, какое из них вызывает проблему.
Шаг 1: Откройте новую вкладку Chrome и перейдите по указанному ниже адресу.
Шаг 2: Нажмите на переключатель, чтобы включить / отключить расширение, и нажмите кнопку «Удалить», чтобы удалить расширение Chrome.
3. Перезагрузите Chrome.
Перед перезапуском Chrome не забудьте сохранить всю свою работу, чтобы не потерять ее. После этого закройте все открытые окна Chrome вместе с вкладками, подождите несколько секунд, а затем перезапустите Chrome.
4. Управление расширениями
Мы обсуждали, как старое несовместимое расширение может вызывать утечку памяти. Но установка слишком большого количества расширений также может привести к проблемам с памятью в Chrome, поскольку они, как правило, потребляют много ресурсов. Выше мы видели, как вы можете удалить или удалить расширение Chrome, но вместо этого вы также можете управлять расширениями и при необходимости быстро отключать / включать их, не вмешиваясь в настройки браузера.
По иронии судьбы, это предполагает установку другого расширения, но это облегчит вам жизнь.
5. Очистите кеш браузера и файлы cookie.
Очистка кеша браузера и файлов cookie может помочь улучшить производительность браузера и исправить несколько проблем, таких как ошибка «нехватки памяти», с которой сталкиваются пользователи. Существует скрытый трюк для очистки кеша и файлов cookie для одного сайта, который не загружается в вашем браузере, или вы можете удалить данные для всех сайтов в настройках браузера. Не забудьте сохранить все открытые вкладки и поработать, прежде чем очищать кеш и файлы cookie, если вы не знаете, что произойдет потом.
6. Очистить временные файлы
Кэш веб-сайтов и файлы cookie помогают быстро загружать соответствующие сайты. А Chrome сохраняет некоторые временные файлы на вашем компьютере с Windows, которые со временем могут накапливаться до нескольких ГБ. Вы удаляете эти временные и старые файлы, чтобы Chrome получил новый пакет данных и предотвратил любые конфликтующие ошибки.
Windows 10 имеет встроенную опцию для удаления временных файлов с каждого диска на вашем компьютере. Вам нужно очистить его для диска, на котором вы установили Chrome. Скорее всего, это диск по умолчанию, обычно это диск C. Вы можете использовать стороннее приложение, если хотите.
7. Запустите Инструмент очистки Chrome.
Google выпустил специальный инструмент для исправления многих распространенных проблем, связанных с браузером Chrome. Его можно загрузить бесплатно, и вы найдете ссылку, которой поделились ниже. Google рекомендует пользователям запускать утилиту один раз, чтобы исправить проблемы, связанные с памятью и сбоями страницы.
8. Отключите аппаратное ускорение.
Шаг 1: Перейдите в «Настройки»> «Дополнительно»> «Система» или введите путь, указанный ниже, в адресной строке.
Шаг 2: Отключите параметр «Использовать аппаратное ускорение, если доступно».
Проверьте еще раз, можете ли вы открыть веб-страницу или получить код ошибки «недостаточно памяти».
9. Новый профиль пользователя
Возможно, профиль пользователя Chrome поврежден. Создание нового профиля может решить проблему с памятью. Шаги просты и не займут больше нескольких минут.
10. Переустановите Chrome.
Кэш и временные файлы, которые собираются со временем, могут привести к ошибкам. Когда пользователи удаляют приложение в Windows, остаются записи реестра и другие файлы, которые также могут вызывать конфликты. Вот почему мы рекомендуем чистую переустановку.
Вы можете использовать надежные приложения, такие как Revo Uninstaller, для удаления приложений в Windows, а также для удаления оставшихся файлов.
Вы можете проверить текущую версию Chrome, установленную на вашем компьютере, по указанному ниже адресу.
После этого вы готовы загрузить и установить последнюю стабильную версию Chrome.
11. Увеличьте лимит памяти.
Это для опытных пользователей, и большинству из вас не придется прибегать к этому. Google имеет установить предел памяти 512 МБ для 32-разрядных и 1,4 ГБ для 64-разрядных систем. Используя ‘–max_old_space_size’, вы можете увеличить этот предел памяти позже до 1 ГБ для 32-разрядных и 4 ГБ для 64-разрядных систем. Обратите внимание, что эти предельные значения памяти предназначены для отдельных вкладок, а не для окон.
На основе продолжающегося обсуждения по снятию этого ограничения в 4 ГБ, вы можете ожидать решения в будущем. Причина в том, что повышение лимита затронет лишь небольшое количество пользователей. Несколько лет назад большинство веб-приложений также не использовали так много памяти, но теперь все по-другому. Некоторые разработчики также отметили, что ограничение памяти до 4 ГБ предотвращает определенные эксплойты, тем самым защищая пользователей.
Однако сейчас все по-другому, и у пользователей есть более мощные машины, работающие под управлением Chrome, и веб-приложения прошли долгий путь. Будем надеяться, что команда разработчиков Google Chrome увеличит ограничение памяти в последующих сборках.
Один из способов увеличить лимит памяти – изменить адрес ссылки Chrome с:
Опять же, здесь задействовано множество переменных, поскольку у разных пользователей разные версии, ОЗУ, ОС и т. Д., Что затрудняет предложение универсального решения.
Вниз по переулку памяти
Вы можете увидеть ошибку «недостаточно памяти» в Chrome, если у вас одновременно открыто слишком много вкладок или слишком много расширений работает в фоновом режиме. Упомянутые выше решения должны помочь вам решить проблему, и вы должны вернуться к просмотру любимых сайтов в кратчайшие сроки.
Следующий:
Firefox выходит на доминирующий рынок браузеров Chrome с Quantum. Стоит ли переходить с Chrome на Firefox? Проверить это.
Fix: Google Chrome Ran Out Of Memory
Almost all of us use the internet on daily basis. And when it comes to internet browsing, Google Chrome is one of the top choice of users. But, even though Google Chrome is highly preferred by the users, you still might face some issues while using it. One of the issues that many people face while using Google Chrome is the “Aw Snap! Chrome ran out of memory” issue.
This issue is exactly what the error message tells you. Your Google Chrome runs out of memory. This is a problem because you will see this message despite having more than enough memory (RAM) on your computer. A lot of Chrome users face this issue out of nowhere. There are no warnings before this issue and there aren’t any specific hints that can help you predict the problem before happening. You might see this error on specific pages or it might be completely random. The error isn’t related to a specific website. This issue, if keeps happening, won’t let you browse normally and will keep showing this page on either random or specific websites.
The cause of issue is not clear. There are many reasons why this might be happening but it is clear that it’s a problem on the Google Chrome end, not on the website’s end. The issue might be caused by some extension or it might be because of a corrupted user profile or it might be because of the wrong Chrome version. Since there can be many reasons of this message, there are multiple solutions of this problem.
So, try to go through troubleshooting and if that doesn’t solve the problem then try each method listed below until the issue is resolved.
Troubleshooting
Method 1: Update to 64-bit
The first thing you should check is whether you have the 64 bit version of Google Chrome or not. This should be your priority especially if you think you have more than enough RAM for Google Chrome. The 64 bit version of Google Chrome is designed to use more memory so if your Chrome is giving this memory error even though you have a lot of memory available then this might be the issue.
If you aren’t sure whether you have a 32 bit or a 64 bit version then follow the steps given below
Once you are done, check whether the problem is still there or not.
Method 2: Using Task Manager
Sometimes killing the Google Chrome from the task manager and then restarting it solves the issue as well. This isn’t a permanent solution but more of a hack which you might have to do over and over. But if nothing else is working then this should come in handy.
These steps are to be performed while your Google Chrome is working and is showing the error.
Once it is closed, re-run the Google Chrome and you shouldn’t see the memory issue page anymore.
Method 3: Clear Cache
Clearing the cache of the browser might be a good option. It will solve the problem if there are any corrupted information stored in there that might be causing this issue.
To clear the cache of the browser, follow the steps given below
Now check whether the issue is gone or not.
Method 4: Disable Extensions
The problem might be caused by an extension as well. You can check whether the problem is because of an extension or not by disabling all the extensions. Once you disable all the extensions check whether the problem is still there. If the problem is gone then that means the problem was because of an extension. You can enable one extension at a time to check which one was causing the issue and then reinstall it.
To disable extensions on your Google Chrome, follow the steps given below
If the problem is gone then enable an extension by checking the Enabled box in front of it. Repeat this for all the extensions and once you find the extension that is causing the issue, delete it by clicking the dustbin box in front of it.
Method 5: Creating New User Profile
If the problem is caused by the information stored by the Google Chrome then changing the name of the default folder of Google Chrome might solve the issue for you. This can happen if your user profile is corrupted.
Follow the steps given below to change the name of your user profile folder
Now start Google Chrome again and check whether the issue still persists or not. Don’t worry about the folder, once you start Chrome again, it will recreate a new Default folder for you automatically.
Как бороться с OutOfMemoryError на практике, или ох уж мне эти базы данных
Предыстория
Для начала нужно понять, как возникает OOM. Кому-то это может быть ещё неизвестно.
Представьте себе, что есть какой-то верхний предел занимаемой оперативки для приложения. Пусть это будет гигабайт ОЗУ.
Само по себе возникновение OOM в каком-то из потоков ещё не означает, что именно этот поток «выжрал» всю свободную память, да и вообще не означает, что именно тот кусок кода, который привёл к OOM, виноват в этом.
Вполне нормальна ситуация, когда какой-то поток чем-то занимался, поедая память, «дозанимался» этим до состояния «ещё немного, и я лопну», и завершил выполнение, приостановившись. А в это время какой-то другой поток решил запросить для своей маленькой работы ещё немного памяти, сборщик мусора попыжылся, конечно, но мусора уже в памяти не нашёл. В этом случае как раз и возникает OOM, не связанный с источником проблемы, когда стектрейс покажет совсем не того виновника падения приложения.
Есть и другой вариант. Около недели я исследовал, как улучшить жизнь парочки наших приложений, чтобы они перестали себя нестабильно вести. И ещё недельку-две потратил на то, чтобы привести их в порядок. В общей сложности пара недель времени, которые растянулись на полтора месяца, ведь занимался я не только этими проблемами.
Из найденного: сторонняя библиотека, и, конечно же, некоторые неучтённые вещи в вызовах хранимых процедур.
В одном приложении симптомы были следующие: в зависимости от нагрузки на сервис, оно могло упасть через сутки, а могло через двое. Если помониторить состояние памяти, то было видно, что приложение постепенно набирало «размер», и в определённый момент просто ложилось.
С другим приложением несколько интереснее. Оно может вести себя хорошо длительный срок, а могло перестать отвечать минут через 10 после перезагрузки, или вдруг внезапно упасть, сожрав всю свободную память (это я уже сейчас вижу, наблюдая за ним). А после обновления версии, когда была изменена и версия Tomcat с 7й до 8й, и JRE, оно вдруг в одну из пятниц (проработав вменяемо до этого ни много ни мало — 2 недели) начало творить такие вещи, что стыдно признаваться в этом. 🙂
В обоих историях очень полезны оказались дампы, благодаря им удалось отыскать все причины падений, подружившись с такими инструментами, как JVisualVM (буду называть его JVVM), Eclipse Memory Analyzing Tool (MAT) и языком OQL (может быть я не умею его правильно готовить в MAT, но мне оказалось легче подружиться с реализацией OQL именно в JVVM).
Ещё вам понадобится свободная оперативка для того, чтобы было куда загружать дампы. Её объём должен быть соизмерим с размером открываемого дампа.
Начало
Итак, начну потихоньку раскрывать карты, и начну именно с JVVM.
Этот инструмент в соединении с jstatd и jmx позволяет удалённо наблюдать за жизнью приложения на сервере: Heap, процессор, PermGen, количество потоков и классов, активность потоков, позволяет проводить профилирование.
Также JVVM расширяем, и я не преминул воспользоваться этой возможностью, установив некоторые плагины, которые позволили куда больше вещей, например, следить и взаимодействать с MBean’ами, наблюдать за деталями хипа, вести длительное наблюдение за приложением, держа в «голове» куда больший период метрик, чем предоставляемый вкладкой Monitor час.
Вот так выглядит набор установленных плагинов.
Visual GC (VGC) позволяет видеть метрики, связанные с хипом.
Вот два скриншота вкладки 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.
Перейдём ко второму приложению:
В нём 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 в рабочие дни, и что даже на выходных оно тоже работает 🙂
Если вы вдруг увидели в своём приложении, что Old-область заполнена — попробуйте просто подождать, когда она переполнится, скорее всего она заполнена уже мусором.
Мусор — это объекты, на которые нет активных ссылок из других объектов, или целые комплексы таких объектов (например, какое-то «облако» взаимосвязанных оъектов может стать мусором, если набор ссылок указывает только на объекты внутри этого «облака», и ни на один объект в этом «облаке» ничто не ссылается «снаружи»).
Это был краткий пересказ того, что я узнал про структуру хипа за время, пока гуглил.
Предпосылки
Итак, случилось сразу две вещи:
1) после перехода на более новые библиотеки/томкеты/джавы в одну из пятниц приложение, которое я уже долгое время веду, вдруг стало вести себя из рук вон плохо спустя две недели после выставления.
2) мне на рефакторинг отдали проект, который тоже вёл себя до некоторого времени не очень хорошо.
Я уже не помню, в каком точно порядке произошли эти события, но после «чёрной пятницы» я решил наконец-то разобраться с дампами памяти детальнее, чтобы это более не было для меня чёрным ящиком. Предупреждаю, что какие-то детали я мог уже запамятовать.
По первому случаю симптомы были такие: все потоки, отвественные за обработку запросов, выжраны, на базу данных открыто всего 11 соединений, и те не сказать, что используются, база говорила, что они в состоянии recv sleep, то есть ожидают, когда же их начнут использовать.
После перезагрузки приложение оживало, но прожить могло недолго, вечером той же пятницы жило дольше всего, но уже после окончания рабочего дня таки снова свалилось. Картина всегда была одинаковой: 11 соединений к базе, и лишь один, вроде бы, что-то делает.
Память, кстати, была на минимуме. Сказать, что OOM привёл меня к поиску причин, не могу, однако полученные знания при поиске причин позволили начать активную борьбу с OOM.
Когда я открыл дамп в JVVM, из него было сложно что-либо понять.
Подсознание подсказывало, что причина где-то в работе с базой.
Поиск среди классов сказал мне, что в памяти аж 29 DataSource, хотя должно быть всего 7.
Это и дало мне точку, от которой можно было бы оттолкнуться, начать распутывать клубок.
Сидеть переклацывать в просмотровщике все эти объекты было некогда, и моё внимание наконец-то привлекла вкладка OQL Console, я подумал, что вот он, момент истины — я или начну использовать её на полную катушку, или так и забью на всё это.
Прежде, чем начать, конечно же был задан вопрос гуглу, и он любезно предоставил шпаргалку (cheat sheet) по использованию OQL в JVVM: http://visualvm.java.net/oqlhelp.html
Сначала обилие сжатой информации привело меня в уныние, но после применения гугл-фу на свет таки появился вот такой OQL-запрос:
Это уже исправленная и дополненная, финальная версия этого запроса 🙂
Результат можно увидеть на скриншоте:
После нажатия на BasicDataSource#7 мы попадаем на нужный объект во вкладке Instances:
Через некоторое время до меня дошло, что есть одно несхождение с конфигурацией, указанной в теге Resource в томкете, в файле /conf/context.xml. Ведь в дампе параметр maxTotal имеет значение 8, в то время, как мы указывали maxActive равным 20…
Тут-то до меня и начало доходить, что приложение жило с неправильной конфигурацией пула соединений все эти две недели!
Для краткости напишу тут, что в случае, если вы используете 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, и «чё-то приуныл»:
Что можно понять из 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.
Удивлению не было предела, честно говоря.
1.2 гига весят соединения в базу.
Каждое соединение весит от 17 до 81 мегабайта.
Ну и ещё «немного» сам пул.
Визуализировать проблему помог отчёт Dominator Tree:
Причиной всех падений оказались километры 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.
И если нажать на надпись See stacktrace, то да, это будет как раз банальный случай, когда какой-то поток вдруг внезапно упал при попытке отмаршалить результат своей работы.
Однако здесь ничто не указывает на причину возникновения OOM, здесь лишь результат. Найти причину мне пока-что, в силу незнания всей магии OQL в MAT, помогает именно JVVM.
Загружаем дамп там, и пытаемся отыскать причину!
Искать мне следует, конечно же, именно вещи, связанные с базой данных, а посему попробуем сначала посмотреть, есть ли в памяти Statement’ы.
Два SybCallableStatement, и один SybPreparedStatement.
Думаю, что дело усложнится, если Statement’ов будет куда больше, но немного подрихтовав один из следующих запросов, указав в where нужные условия, думаю, всё у Вас получится. Плюс, конечно же, стоит хорошенько посмотреть в MAT, что за результаты пытается отмаршалить поток, какой объект, и станет понятнее, какой именно из Statement’ов необходимо искать.
Не то, это «внутренние» вызовы.
А вот и дичь!
Для чистоты эксперимента можно кинуть такой же запрос в любимой БД-IDE, и он будет очень долго отрабатывать, а если покопаться в недрах хранимки, то будет понятно, что там просто из базы, которая нам не принадлежит, выбирается 2 миллиона строк по такому запросу с такими параметрами. Эти два миллиона даже влазят в память приложения, но вот попытка отмаршалить результат становится фатальной для приложения. Такое себе харакири. 🙂
При этом GC старательно убирает все улики, но не спасло его это, всё же источник остался в памяти, и он будет наказан.
Почему-то после всего этого рассказа почувствовал себя тем ещё неудачником.
Прощание
Вот и закончилось моё повествование, надеюсь, Вам понравилось 🙂
Хотел бы выразить благодарность своему начальнику, он дал мне время во всём этом разобраться. Считаю эти новые знания очень полезными.
Спасибо девушкам из Scorini за неизменно вкусный кофе, но они не прочтут этих слов благодарности — я даже сомневаюсь, что они знают о существовании Хабрахабра 🙂
Хотелось бы увидеть в комментариях ещё больше полезной инфы и дополнений, буду очень благодарен.
Думаю, самое время почитать документацию к MAT…
UPD2 (2015-10-28) | Случай номер два три
(Было принято решение дописать это сюда как апдейт, а не пилить новую статью о том же самом):
Ещё один интересный случай, но уже с Оракловой базой.
Один из проектов использует фичу с XML, проводит поиски по содержимому сохранённого XML-документа. В общем, этот проект иногда давал о себе знать тем, что вдруг внезапно один из инстансов переставал подавать признаки жизни.
Почуяв «хороший» случай потренироваться на кошках, я решил посмотреть его дампы памяти.
Первое, что я увидел, было «у вас тут много коннектов в памяти осталось». 21к. И какой-то интересный oracle.xdb.XMLType тоже давал жару. «Но это же Оракл!», вертелось у меня в голове. Забегая вперёд скажу что таки да, он виноват.
Итак, видим кучу T4CConnection, которые лежат в HashMap$Entry. Обратил внимание сразу, что вроде бы и SoftHashMap, что, вроде как, должно означать, что оно не должно вырастать до таких размеров. Но результат видите и сами — 50-60 килобайт в коннекте, и их реально МНОГО.
Посмотрев, что собой представляют HashMap$Entry — увидел, что примерно картина одинакова, всё связано с SoftHashMap, с Оракловыми коннектами.
Что, собственно, подтверждалось такой картинкой. HashMap$Entry было просто море, и они более-менее сакуммулировались внутри oracle.xdb.SoftHashMap.
В следующем дампе картина была примерно такой же. По Dominator Tree было видно, что внутри каждого Entry находится тяжёлый такой BinXmlProcessorImpl.
-=-=-
Если учесть, что я в тот момент был не силён в том, что такое 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
Утвердившись, что тут всё-таки косяк у Оракла, дело оставалось за малым.
Попросил администратора БД посмотреть информацию по обнаруженной проблеме: