Tomcat постепенно исчерпывает память с развернутыми приложениями WebSocket

У меня Tomcat 8.5.9, запущенный на AWS, с развернутыми 10 различными приложениями WebSocket, каждое из которых в основном действует как брокер сообщений. Коннектор https использует протокол Http11NioProtocol. Единственный параметр, который я установил, это maxThreads=200 вместе с информацией о сертификате.

Объем запросов не очень высок. Он работает с утра понедельника, и вот что говорит статус менеджера:

Макс темы: 200
Текущий счетчик потока: 38
Текущий поток занят: 0
Оставьте в живых количество сокетов: 1
Максимальное время обработки: 234 мс
Время обработки: 17.254 с
Количество запросов: 33351
Количество ошибок: 325
Получено байт: 0,00 МБ
Отправлено байт: 34,07 МБ

Через несколько дней я замечаю, что использование памяти продолжает расти. Я должен перезапускать сервисы Tomcat примерно каждые две недели, чтобы предотвратить получение исключения OutOfMemoryException.

Я принимал дампы кучи и анализировал с помощью Eclipse MAT, который всегда указывает на то, что класс WsFrameServer является подозреваемой проблемой. Самый последний дамп отображает следующее:

5 146 экземпляров "org.apache.tomcat.websocket.server.WsFrameServer",
загруженные "java.net.URLClassLoader @ 0x6c0047c28" занимают 1 383 143 200
(73,13%) байтов. На эти экземпляры ссылаются из одного экземпляра
"Java.util.concurrent.ConcurrentHashMap$Node[]"

Дерево Доминаторов в настоящее время содержит 106 000 записей, большинство из которых - класс WsFrameServer.

Я что-то не так делаю или это "нормально"? Есть ли какие-то особые настройки на Tomcat или Connector, которые я должен установить, чтобы этого не происходило?

Заранее спасибо.

РЕДАКТИРОВАТЬ: Я не уверен, если это полезно, но вот как выглядит монитор VisualVM:

VisualVM Monitor

3 ответа

Трудно быть уверенным без подробностей, но это, вероятно, связано с сохранением вашего сеанса. Я думаю, что происходит то, что WsFrameServer который расширяется WsFrameBase добавлен в сессию.
Если у вас есть неограниченная политика хранения сеансов, то в конечном итоге вам не хватит памяти.

Попробуйте установить не-0 sessionTimeout

Код отсутствует в вашем вопросе. (особенно, как вы управляете соединением через websocket)

Вы использовали tomcat в асинхронном режиме со списком соединений где-то?

Вы не забыли привязать событие ошибки AND к коду, удаляющему неисправное соединение из списка?

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

На скриншоте вашей VisualVM видно, что использование памяти относительно нормальное: с течением времени используется больше памяти, после GC потребление памяти снижается.

Поэтому мне интересно, будет ли ваше приложение действительно зависать из-за OOM. Вы можете попробовать его в своей тестовой среде и проанализировать дамп JOM-файла OOM, что более полезно.

Кстати, я предлагаю VisualVM поверх MAT, потому что MAT будет включать некоторые недоступные объекты в качестве корня GC. Это сделает анализ памяти очень неэффективным и даст другой результат, чем другие инструменты, которые я встречал в одном из наших проектов.

Другие вопросы по тегам