Вызывает ли Postgres JDBC LazyCleaner утечку памяти загрузчика классов?

У меня есть веб-приложение Spring Boot, которое развертывается несколько раз в день, поэтому необходимо выполнить чистое развертывание. Tomcat сообщает об утечке памяти, и MAT указывает мне на

Я использую postgresql-42.6.0.jar и поместил этот JAR в каталог Tomcat 10.1 ./lib (как и должны быть драйверы JDBC, если честно). Мне кажется, что веб-приложение, присутствующее при запуске Tomcat, загружается org.postgresql.util.LazyCleaner, которое затем запускает поток «PostgreSQL-JDBC-Cleaner». Поскольку поток наследует AccessControlContext ProtectionDomain, загруженный загрузчиком классов веб-приложения, этот загрузчик классов всегда будет иметь ссылку, которую невозможно получить, что приведет к утечке памяти.

Я не могу найти в Интернете ничего, что у других тоже была бы такая проблема. Я что-то пропустил?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
121
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

LazyCleaner был представлен в версии 42.6.0 как попытка борьбы с утечками памяти (https://github.com/pgjdbc/pgjdbc/issues/1360 и https://github.com/pgjdbc/pgjdbc/ выпуски/1431). Класс использует PhantomReference Java, чтобы определить, когда «референтный» объект был собран, а затем запускает связанное с ним «CleaningAction». Все это выполняется в потоке PostgreSQL-JDBC-Cleaner. Если поток вообще не имеет «референтных» объектов в пределах срока жизни (по умолчанию — 30 с), поток завершается. Регистрация любого «референтного» объекта при необходимости создаст новый поток.

Какие части postgresql-42.6.0.jar используют LazyCleaner?

PgConnection.java
cleanable = LazyCleaner.getInstance().register(leakHandle, finalizeAction);

StreamWrapper.java
cleaner = LazyCleaner.getInstance().register(leakHandle, tempFileHolder);

SharedTimer.java
this.timerCleanup = LazyCleaner.getInstance().register(refCount, new TimerCleanup(timer));

Так что это:

  • Каждое PgConnection регистрируется с помощью PgConnectionCleaningAction.
  • Каждый psql StreamWrapper регистрируется с помощью TempFileHolder (реализует CleaningAction) для закрытия потоков и удаления временных файлов.
  • Каждый psql SharedTimer регистрируется с помощью TimerCleanup для отмены таймера.

Последние два являются временными регистрациями, но PgConnection является проблемой. В установке с

  • Tomcat с postgresql-42.6.0.jar в /lib для общего загрузчика классов
  • Несколько веб-приложений, использующих PSQL
  • Каждое веб-приложение использует пул соединений, который некоторое время поддерживает соединения.

каждое веб-приложение будет иметь экземпляры PgConnection, зарегистрированные в LazyCleaner, который используется как общая библиотека (по замыслу). Таким образом, повторное развертывание одного веб-приложения не остановит поток LazyCleaner, поскольку в других веб-приложениях все еще зарегистрированы PgConnections.

Поток наследует AccessControlContext через трассировку стека при запуске, в результате чего исходный поток LazyCleaner будет содержать ссылку на ProtectionDomain веб-приложения, которое первоначально запустило поток. Как описано выше, поток LazyCleaner никогда не завершается и, таким образом, удерживает загрузчик классов веб-приложения от gc.

На данный момент проблема решается переходом на postgresql-42.5.6.jar.

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