This is very likely to create a memory leak. Stack trace of thread錯誤分析
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
,解決方案在後面的部落格解決。