사실 어제 okjsp 에 문의했던 거긴 합니다 ㅎㅎ;; http://www.okjsp.pe.kr/seq/206861
어쩜 jvm, was 에 대한 이해가 덜되어 하는 질문인것 같네요. (모든 상황은 로컬개발환경을 전제합니다 ㅋ tomcat 6.0.35, eclipse juno, jdk 1.6)
요 며칠동안 tomcat console 경고문구때문에 삽질을 좀 했습니다. sqljdbc.jar 를 maven repository에 넣고 maven 을 class path로 잡아주니 class 파일 수정후에 동적으로 리로드 될때에 sqljdbc_auth.dll 이라는 파일을 다른 오브젝트에서 이미 참조중이라며 memory leak 경고가 나왔습니다.
그래서 고민하다가 맘편히 web-inf/lib 이하에 두자는 생각으로 web-inf/lib 이하에 두었습니다. 그러자 sqljdbc_auth.dll 파일에 대한 memory leak 대신에 A web application registered the JBDC driver [sqljdbc드라이버..] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 위와 같은 memory leak 경고가 나왔습니다 ㅠㅠ
이 경고가 이전에도 있었는지는 (메이븐 적용전) 모르겠습니다. 바보같이;;; 모든 로컬개발환경을 새로 갖추면서 로그까지 다 지웠....ㅠㅠㅠ 그래서 구글링을 하다보니 http://www.coderanch.com/t/498919/Tomcat/Memory-Leak-repeat-deploy-undeploy 이런 걸 찾게 되었고 질문자가 감동받은 해결방안인 tomcat/lib 이하에 sqljdbc.jar를 두었습니다. 그러자 경고문구가 안나오네요 -_-;;;
다음번 war배포때에는 개발서버나 실서버에 톰캣lib 에 sqljdbc.jar를 넣어야하는 귀차니즘 1회가 있지만 맘이 편하네요 ㅎㅎ;;
........
하지만 대체 왜?! 이런 문제가 있을까요?? 제목처럼 제 생각엔 class path(tomcat 단위, 프로젝트 단위 등?) 가 문제이고 class loader 에 따른 문제인 것 같은데.. 무엇이 문제일까요?ㅠㅠ
4개의 의견 from SLiPP
나도 정확하지는 않지만 문수 너의 질문에서 유추해보면 다음과 같은 상황이라고 생각한다.
tomcat/lib는 해당 tomcat에 배포하는 모든 웹 애플리케이션에서 참조하는 라이브러리이고, maven 저장소와 WEB-INF/lib의 저장소는 각각의 웹 애플리케이션에서 사용하는 라이브러리를 관리한다. 따라서 maven 저장소와 WEB-INF/lib에 대한 차이는 없을 거야. 예를 들어 WTP를 사용한다면 배포하는 시점에 pom.xml에 설정되어 있는 jar 파일이 WEB-INF/lib에 복사되기 때문에 결과적으로는 똑같다고 생각해도 된다.
그렇다면 tomcat/lib와 WEB-INF/lib의 차이가 무엇인지를 찾아야 될 듯하다. memory leak 경고가 발생하는 시점이 class 파일 수정 후에 동적으로 리도드 될 때 발생하는 것이라고 했으니 그 차이는 명백할 듯하다. 동적으로 reload 된다는 것은 tomcat 인스턴스는 동작하고 있는 상태에서 웹 애플리케이션만 재배포되고 재시작되는 것이다. 따라서 웹 애플리케이션이 리로드 되더라도 tomcat 인스턴스가 재시작되는 것은 아니기 때문에 tomcat 인스턴스가 계속해서 sqljdbc_auth.dll에 대한 참조를 가지고 있는 상태가 된다. 즉 WEB_INF/lib에 sqljdbc.jar을 둘 경우 웹 애플리케이션을 재시작하면 sqljdbc.jar에 대한 참조는 해제되지만 tomcat 인스턴스가 sqljdbc_auth.dll에 대한 참조를 계속 가지고 있는 상태가 되는 것이지..
하지만 tomcat/lib에 sqljdbc.jar 파일을 둔 다면 웹 애플리케이션이 리로드 되더라도 sqljdbc.jar에 대한 참조는 해제되지 않고 유지되기 때문에 위와 같은 경고 문구는 발생하지 않을테고. WTP를 재시작하면 위와 같은 경고 문구는 발생하지 않을 듯하다.
따라서 개발 서버나 실 서버는 reloadable을 false로 설정하고 사용하기 때문에 위와 같은 에러가 발생할 가능성은 없다고 생각한다. 따라서 WEB-INF/lib에 두어도 무방하지 않을까 생각한다. 단, 로컬 개발 환경이 이슈인데 로컬 개발에서 reloadable을 false로 놓고 사용하거나 가능한 reloadable이 발생하지 않도록 개발할 수 밖에 없을 듯하다.
그렇지 않으면 네가 말한데로 새로운 서버 배포할 때 마다 tomcat/lib에 sqljdbc.jar 파일을 넣어주어야 하는 불편함이 생길 듯하다. 이는 장기적으로 유지보수 시점에 실수할 가능성도 많기 때문에 가능한 사용하지 않는 것이 좋겠다. 대안이 있다면 jdbc driver를 다른 놈으로 변경하거나...
http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html 문서 보면 tomcat이 class를 loading하는 순서와 방법에 대해 살펴볼 수 있다.
아무리 봐도... 질문자는 web-inf/lib 밑에 넣는 부분에 감동받았는데요... tomcat/lib 에 넣었더니 memory leak 이 나서, web-inf/lib 밑으로 넣었더니 없어졌다... 라는 의미로 보입니다.
마지막 Warning 메시지는 Memory Leak 이 발생했다는 의미가 아닙니다. Tomcat 이 정상적으로 Driver를 해제 했다는 의미 입니다. 이 메시지가 나오는 이유는 http://wiki.apache.org/tomcat/MemoryLeakProtection#jdbc 여기에 설명되어 있고요.
겪으셨던 문제(?)와 정확하게 동일한 질문은 http://stackoverflow.com/questions/3320400/to-prevent-a-memory-leak-the-jdbc-driver-has-been-forcibly-unregistered 이 질문 입니다.
tomcat/lib 에 JDBC Driver를 넣어야 하는 문제는 꽤 오래된 이야기인데요, http://stackoverflow.com/questions/6981564/why-jdbc-driver-must-been-put-in-tomcat-home-lib-folder 쪽에서 좀 상세한 설명이 있습니다.
(개인적으로는, WEB-INF/lib 에 넣어버리고, Memory Leak 관련 Warning은 무시하는 쪽으로 썼었습니다.)
@자바지기 답변 감사합니다. 우선 tomcat/lib 이하에 두고 있어요 ㅎㅎ;; 개발/실 서버에는 역시 reloadable에 false값을 주고 있는데 이것 관련해서 궁금한 사항이 있는데 다음 기회때에 좀 여쭐게요. 참고하라고 주신 문서 잘 보겠습니다 ㅋ 감사합니다 :) @kenny 아;;; 질문자 분 바로 윗분이 다신 답글을 그대로 행했더니 경고문이 안나와서 해석도 제대로 않고 제가 글을 작성했네요 ㅎㅎ -_-;;; 아 메모리릭 발생했다는 의미가 아니었군요;;; -_-;;;;; 쿨럭...참고하라고 주신 문서 잘 보겠습니다 오오... 감사합니다 ㅎㅎ
의견을 남기기 위해서는 SLiPP 계정이 필요합니다.
안심하세요! 회원가입/로그인 후에도 작성하시던 내용은 안전하게 보존됩니다.
SLiPP 계정으로 로그인하세요.
또는, SNS 계정으로 로그인하세요.