ㅇ.ㅇ
[Tomcat] Warning - To Prevent a Memory Leak, the JDBC Driver Has Been Forcibly Unregistered 본문
[Tomcat] Warning - To Prevent a Memory Leak, the JDBC Driver Has Been Forcibly Unregistered
yun_ 2023. 3. 22. 08:36
상황
톰캣에서 에러는 아니지만 메모리릭 관련 워닝이 발견되어 찾아보았다.
에러 내용
The web application registered the JDBC driver [org.postgresql.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
메시지 의미
Tomcat은 웹 애플리케이션을 배포할 때 postgresql Driver JDBC 클래스가 등록되었지만, 동일한 애플리케이션을 제거할 때 등록 해제되지 않았다는 것을 알려주고 있다.
문제 원인
문제의 원인은 JDBC 드라이버의 부적절한 구현이라고 한다. JDBC 드라이버는 어플리케이션이 언디플로이 되면 등록해제가 되어야 한다. 여기서 JDBC 드라이버는 데이터베이스에 접속하기 위한 java.sql.Driver 인터페이스를 확장한 클래스로 여러 방법으로 로드 및 등록할 수 있다. Tomcat은 SPI를 이용해서 웹 어플리케이션의 WEB-INF/lib 디렉토리에서 찾을 수 있는 JDBC 4.0 호환 드라이버 클래스를 자동으로 로드한다. 이를 통해 드라이버 클래스를 수동으로 등록할 필요 없이 데이터베이스와의 연결을 쉽게 설정할 수 있다.
웹 응용 프로그램의 배포를 취소할 때는 해당 응용 프로그램이 제공하는 모든 드라이버의 등록도 취소해야 하는데 그렇지 않으면 드라이버가 Tomcat에 등록된 상태로 남아있게 되어서 메모리 누수(memory leak)가 발생하기 때문이다.
톰캣은 6.0.24버전부터 이러한 누수를 감지하고 자동으로 모든 드라이버를 등록 해제해 준다. 하지만 다른 웹 서버에서는 이런 기능을 제공하지 않을 수 있으므로 경고메시지 자체가 문제 파악에 도움을 주니까 이렇게 워닝은 계속 해주는 상태인듯하다.
해결 방법
- 최신 톰캣을 설치한다
- 종료 시 드라이버를 수동으로 등록 취소하는 코드를 구현한다
- jdbc jar를 애플리케이션의 WEB-INF/lib 에서 tomcat의 /lib 디렉토리로 이동시킨다
결론
톰캣 실행 시 등록된 jdbc가 톰캣 종료 시에 jdbc가 등록 취소가 되어있지 않아 경고를 보내는 것이며, 톰캣 6.0.24 버전부터는 자동으로 톰캣 내에서 메모리 릭에 관하여 처리하므로 경고메시지 자체를 무시해도 된다고 한다. 그렇지만 어떤 부분에서 메모리릭이 나는지는 더 파악해 보는 것이 좋을 듯하다.
+ ) SPI 란?
Java SPI(java service provider interface)는 자바에서 제공하는 기능으로, 라이브러리나 프레임워크에서 인터페이스를 정의하고, 해당 인터페이스를 구현하는 다양한 라이브러리나 프레임워크들을 쉽게 찾아서 사용할 수 있도록 지원하는 방법이다.
일반적으로 SPI는 인터페이스와 해당 인터페이스를 구현한 클래스의 집합으로 이루어져 있는데, 인터페이스를 제공하는 라이브러리나 프레임워크는 자신의 인터페이스를 구현한 클래스를 찾아서 런타임에 동적으로 로딩할 수 있다. 이렇게 함으로써, 라이브러리나 프레임워크는 클래스패스(자바 애플리케이션이 클래스 파일을 찾는 경로)를 굳이 수정하지 않고도 다양한 구현체를 사용할 수 있는 것이다.
(자바에서 제공하는 JDBC, Logging, XML 파서, Security 등의 다양한 기술에서 Java SPI를 사용하고 있다)
+ ) JDBC 드라이버 로드 순서
JDBC 드라이버를 로드하는 순서이다.
- 애플리케이션에서 DriverManager 클래스를 이용하여 데이터베이스에 접속한다.
- DriverManager 클래스는 자바 SPI를 이용하여, META-INF/services/java.sql.Driver 파일을 읽어와서 등록된 모든 JDBC 드라이버 클래스를 찾는다.
- JDBC 드라이버 클래스는 java.sql.Driver 인터페이스를 구현하고 있어야한다.
- DriverManager 클래스는 이 중에서 적절한 JDBC 드라이버 클래스를 선택하여, 해당 클래스를 로드한다.
- 선택된 JDBC 드라이버 클래스는 DriverManager 클래스에 등록되어, 데이터베이스에 접속할 때 사용된다.
즉, JDBC 드라이버는 META-INF/services/java.sql.Driver 파일에 등록된 클래스들 중에서 적절한 클래스를 선택하여 로드하게 되는데, 이때 선택된 클래스는 java.sql.Driver 인터페이스를 구현하고 있어야 하고, Driver Manager 클래스에 등록되어 사용 이런 식으로 jdbc 드라이버는 로드된다.
(참고)
https://stackoverflow.com/questions/3320400/to-prevent-a-memory-leak-the-jdbc-driver-has-been-forcibly-unregistered
https://www.baeldung.com/tomcat-jdbc-memory-leak
'Error' 카테고리의 다른 글
[WebSocket] Error - The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method (4) | 2023.05.20 |
---|---|
[Tomcat] 톰캣 다중 구동환경 시 로그인 끊김 현상 / jsessionid 충돌 (0) | 2023.04.06 |
[Java] Error - Invalid property 'maxWait' of bean class (0) | 2023.03.29 |
[Java] Error - Illegal hexadecimal character q at index 0 (0) | 2023.03.23 |
[Jenkins] 젠킨스 설정 시 스크립트 에러 (0) | 2023.02.20 |