Изучая подозрительную утечку памяти в нашем приложении Java, мы обнаружили, что большая часть памяти использовалась экземплярами SSLSessionContextImpl
, которые создавались соединителем MySQL - по одному экземпляру на соединение.
Это стало для нас проблемой, поскольку начиная с OpenJDK 8u222 каждый экземпляр SSLSessionContextImpl
содержит кэш с начальной емкостью (20480 / 0.75) + 1 = 27307
(см. JDK-8210985 и Источник JDK ). Это в сочетании с пулом соединений Hikari, который создавал десять новых соединений каждые полчаса (поведение по умолчанию), означало, что через неделю у нас было около 1 ГБ мертвых SSLSessionContextImpl
экземпляров. Они были в пуле памяти временного поколения и фантомно на них ссылались AbandonedConnectionCleanupThread
класс , и мы видели наше приложение d ie из-за нехватки памяти (в контейнере Docker ограничено 1 ГБ), поэтому я предполагаю, что надлежащий G C не может быть выполнен вовремя на накопленных экземплярах.
Наивно, кажется, что разъем MySQL не ведет себя вполне верно, и что для того же сервера базы данных, он должен повторно использовать тот же SSLSessionContextImpl
- в конце концов, JavaDo c SSLSessionContext
интерфейса (который он реализует) говорит:
A SSLSessionContext
представляет собой набор SSLSessions
, связанный с одним объектом. Например, это может быть связано с сервером или клиентом, который участвует во многих сеансах одновременно.
Это прекрасно описывает наш сценарий! Тем не менее, Connector создает новый SSLSessionContext
для каждого соединения.
Итак, два вопроса:
- Почему разъем MySQL не использует
SSLContext
повторно? (Конечно, мы не можем читать мысли разработчиков - но есть ли причины, по которым кто-то может не захотеть использовать его повторно?) - Можем ли мы каким-то образом заставить его повторно использовать
SSLContext
?