1、問題描述
啟動tomcat部署項目時,報
This is very likely to create a memory leak. Stack trace of thread
錯誤。
29-May-2018 12:30:09.322 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal One or more Filters failed to start. Full details will be found in the appropriate container log file
29-May-2018 12:30:09.323 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.startInternal Context [] startup failed due to previous errors
29-May-2018 12:30:09.427 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ROOT] registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
29-May-2018 12:30:09.427 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ROOT] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
29-May-2018 12:30:09.428 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [ROOT] registered the JDBC driver [org.h2.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
29-May-2018 12:30:09.428 WARNING [localhost-startStop-1] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:64)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
2、問題原因
tomcat啟動奔潰,同時釋放了jdbc連接。
3、解決方案
這種異常造成的原因千奇百怪,並沒有統一的處理方案,以下是我遇到的不同情況采取的幾種解決方案。
3.1、存在多個tomcat子線程
啟動前tomcat意外退出,使用
ps -ef | grep "tomcat名稱"
查看是不是有多個tomcat在啟動,若有,Kill掉。
3.2、調整JVM參數
JAVA_OPTS='-server -Xms5120m -Xmx10240m -XX:PermSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=5120m '
3.3、去掉tomcat監聽
tomcat 6.025以后引入了內存泄露偵測,對於垃圾回收不能處理的對像,它就會做日志。去掉監聽的方法也很簡單:
在tomcat的server.xml文件中,把
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
這個監聽給關了。
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
3.4、其他
如果以上方案無法解決問題,只能逐步排查,排查方案如下:
1.使用“之前部署正常的分支”(我們記為hoaven分支)部署項目;
2.若tomcat能正常啟動,說明tomcat或服務器沒有問題,檢查自己的代碼;
3.逐步檢查自己的代碼:從hoaven分支checkout一個分支(fixbug),然后將自己寫的代碼一點一點移至fixbug分支。
4.每移動一次代碼,部署一次,若正常啟動,繼續移動代碼;若報出以上錯誤,停止移動,檢查本次移動的代碼。
其實3.4方法很有效,特別是檢查肉眼無法明了的莫名其妙的的bug。
記錄下我某一次檢查以上bug采用的3.4方案,得出的結果:
代碼中,有一處注入報錯很奇怪:
@Slf4j
@Component
public class RestAuthFilter extends FormAuthenticationFilter {
@Resource
MobileDeviceService mobileDeviceService;
@Resource
UserService userService;
...
}
@Slf4j
@Service
public class MobileDeviceServiceImpl implements MobileDeviceService {
@Resource
IHddBaseService hddBaseService;
...
}
MobileDeviceService
和UserService
上的@Resource
改為@Autowired
部署則沒有問題,思考一下:@Resource屬於jdk的注解,@Autowired屬於spring的注解,應該是注入RestAuthFilter時,在spring容器中沒有找到MobileDeviceService和UserService的實例,@Resource
會強制將MobileDeviceService
和UserService
注入進來,而@Autowired
采取的措施是不注入(或注入null
)。這樣一來,就會有新的問題,MobileDeviceService
和UserService
實例為null
,解決方案在后面的博客解決。