У меня есть веб-приложение 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, загруженный загрузчиком классов веб-приложения, этот загрузчик классов всегда будет иметь ссылку, которую невозможно получить, что приведет к утечке памяти.
Я не могу найти в Интернете ничего, что у других тоже была бы такая проблема. Я что-то пропустил?




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 является проблемой. В установке с
каждое веб-приложение будет иметь экземпляры PgConnection, зарегистрированные в LazyCleaner, который используется как общая библиотека (по замыслу). Таким образом, повторное развертывание одного веб-приложения не остановит поток LazyCleaner, поскольку в других веб-приложениях все еще зарегистрированы PgConnections.
Поток наследует AccessControlContext через трассировку стека при запуске, в результате чего исходный поток LazyCleaner будет содержать ссылку на ProtectionDomain веб-приложения, которое первоначально запустило поток. Как описано выше, поток LazyCleaner никогда не завершается и, таким образом, удерживает загрузчик классов веб-приложения от gc.
На данный момент проблема решается переходом на postgresql-42.5.6.jar.