JAVAEE - Используемая куча памяти просто продолжает увеличиваться, пока все не сломается
Я запускаю веб-приложение среднего размера из джерси под tomcat. Я обнаружил, что приложение продолжает зависать после определенного количества времени выполнения (пару дней) из-за проблемы нехватки памяти, я уже увеличил размер кучи, но это не проблема, поскольку я где-то сталкиваюсь с утечкой памяти.
Я искал способы отладки этого безрезультатно. Я использую инструмент под названием YouKit Java, чтобы помочь мне в этом, и я понял, что используемая куча памяти продолжает расти бесконечно, пока не сломается. Сборка мусора не запускается в любой момент.
Использование памяти в куче после 16 часов Я запускал приложение отладки на всю ночь, и даже при минимальной или бесполезной работе это происходит: размер используемой кучи увеличивается с пары МБ до XXXMB (> 1 ГБ в prod) без нагрузки на нее вообще. После принудительного сбора мусора использование памяти возвращается к норме.
Слева внезапное снижение после того, как я заставляю GC. Справа память через пару минут после GC
На следующем рисунке показано, как используемая память снова увеличивается после моего принудительного GC с базовым использованием приложения: перезагрузка страницы, некоторые запросы get, которые возвращают данные из db (sqlite), и некоторые post-запросы, которые записывают в db и открывают некоторые сокеты. Обратите внимание, что для всего, что я тестировал, я также запускаю противоположную команду, которая должна отменить мои изменения. но память просто продолжает расти.
Я сделал снимок памяти, чтобы просмотреть, что происходит. Самые большие объектные доминанты показывают огромное древовидность объекта java.lang.ref.Finalizer, зная, что я никогда не вызываю какой-либо метод finalize (хотя я об этом не знаю)
Так что я очень запутался в этом, Java не самая большая моя сила, и у меня много трудных моментов для отладки этого. Мне интересно, есть ли что-то, что мешает запуску GC и вызывает это? (Как я вижу, после принудительного выполнения GC все возвращается к более нормальному состоянию). Может ли это быть вызвано TOMCAT или самой майкой?
Примечания к приложению: это API, который позволяет создавать tcp туннель в фоновом режиме (сокеты сервера и клиента). Каждый туннель порожден в потоке. Он также выполняет выборку и запись данных в базу данных sqlite. Я пытался быть уверенным, что все закрыто должным образом (соединения БД, запросы, сокеты и нет ссылок...), когда работа сделана. Что касается туннелей, я полагаюсь на слегка отредактированную версию библиотеки под названием javatunnel (она также может оказаться преступником, но не может найти ничего, что доказывает это)
2 ответа
Возможно, сокет закрыт неправильно, так что сборщик мусора не может освободить их и связанные объекты? Я думаю, вы должны попытаться глубже исследовать это.
Вы можете активировать журналы сборщика мусора, чтобы определить, когда он запускается. Вы должны добавить флаги -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps
при запуске JVM.
Я понял, что используемая память кучи продолжает расти бесконечно, пока не сломается. Сборка мусора не запускается в любой момент.
В этом случае вы должны взглянуть на параметры GC в аргументах запуска JVM. Каково соотношение вашего максимального старого размера и максимального нового размера. Если максимальный старый размер слишком велик по сравнению с максимальным новым размером, ваши объекты будут продолжать переходить от выжившего к старому поколению и не будут собирать мусор до тех пор, пока размер старого поколения не достигнет порогового значения, которое, я полагаю,> 75% по умолчанию.
Итак, проверьте настройки GC. Это может помочь.