Tomcat 警告“為防止內存洩漏,已強制註銷 JDBC 驅動程序”
一、概述
在本教程中,我們將查看 Tomcat 警告消息,該消息通知我們它強制取消註冊 JDBC 驅動程序。我們將探討該消息的含義、其根本原因以及我們可以採取哪些措施來緩解它。
2.信息和意義
消息的版本可能如下:
SEVERE: A web application registered the JBDC driver [oracle.jdbc.driver.OracleDriver]
but failed to unregister it when the web application was stopped.
To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
通過以上內容,Tomcat 通知我們,JDBC 驅動程序類OracleDriver
在我們部署 Web 應用程序時已註冊,但在取消部署同一應用程序時並未取消註冊。
我們可以通過多種方式加載和註冊 JDBC 驅動程序,它本質上是一個擴展java.sql.Driver
接口的類。 Tomcat 使用 Java 服務提供者接口 (SPI) 並自動加載它可以在 Web 應用程序的WEB-INF/lib
目錄下找到的任何 JDBC 4.0 兼容的驅動程序類。
當我們取消部署 Web 應用程序時,我們還必須取消註冊它帶來的任何驅動程序。否則,它們仍然在 Tomcat 中註冊。這會造成內存洩漏,直到我們關閉整個 Web 服務器。
從 6.0.24 版本開始,Tomcat 檢測到這種類型的洩漏並強制註銷所有洩漏的驅動程序。但是,它仍然會通知我們該問題,如果我們在另一個不支持此功能的 Web 服務器上部署相同的應用程序,這將非常有幫助。
3. 根本原因和潛在問題
問題的原因在於 JDBC 驅動程序的執行不當。它應該監聽應用程序取消部署事件並取消註冊自己。
當 Java SPI 加載 JDBC 驅動程序時,它使用當前上下文類加載器加載它。由於驅動程序位於應用程序的WEB-INF/lib
下,SPI 使用其類加載器加載它。以這種方式加載的驅動程序註冊到DriverManager
類,它是一個 JVM 單例。如果這沒有發生,它會在加載的類中引入內存洩漏。
當我們取消部署 Web 應用程序時,它的類加載器會被垃圾回收。另一方面, DriverManager
仍然引用了防止垃圾收集的 JDBC 驅動程序。如果我們再次部署相同的 Web 應用程序,則會創建一個新的類加載器,並且 SPI 會再次加載相同的 JDBC 驅動程序。這實際上是內存洩漏。
4. 緩解措施
有多種方法可以緩解這個問題。
4.1。使用較新的 Tomcat 版本
從 6.0.24 版本開始,Tomcat 會自動為我們處理這個問題。這意味著我們可以放心地忽略警告信息。
4.2.關機時手動註銷
我們可以在任何應用程序關閉回調中手動取消註冊驅動程序。在我們的應用程序將加載一個 JDBC 驅動程序的標準情況下,我們可以用一行代碼來做到這一點:
DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement());
需要注意的是,雖然 Tomcat 調用了動作註銷,但是DriverManager
方法稱為註銷。
4.3.移動 JDBC Jar
官方處理這個問題的方法是將 JDBC 驅動 jar 文件從應用程序的WEB-INF/lib
移動到 Tomcat 的 / lib
目錄。由於 / lib
目錄下的所有 jar 也都在 classpath 上,因此 Tomcat 仍然會自動加載驅動程序,但在自己的 classloader 下。
當我們部署應用程序時,Tomcat 不會加載任何驅動程序實現,因為WEB-INF/lib
下不會有任何驅動程序實現。這意味著我們可以在不加載任何新內容的情況下安全地取消部署和重新部署它,從而防止任何洩漏。
5. 結論
在本文中,我們討論了來自 Tomcat 的 JDBC 驅動程序強制註銷警告消息的含義。我們還研究了它的根本原因以及修復它的可能方法。