最近又遇到一個奇怪的事情,一個非常簡單的程式,就是web調用一下從資料庫讀取一批資料出來顯示,程式剛開始一點問題沒有,過一段時間就突然死掉了,所有的查詢都沒有反應。
探索+折磨:
剛開始用的辦法真的叫做非常原始。因為卡住連異常都不報,那很可能是什麼沒有設定逾時。開始把web連接配接和資料庫連接配接的逾時設定檢查并調整了一遍,但是問題依然沒有解決。
接着看覺得又像是資料庫取不到連結,這可能是資料庫連接配接池耗盡,那麼應該連接配接都沒有釋放。到mysql中查目前連接配接數,非常正常,感覺也不是連接配接的問題。當程式卡住的時候,其他和資料庫連接配接的程式都很正常,自己的程式一重新開機也是正常的。是以應該也不是連接配接數耗盡的問題。期間也把程式的目前線程列印出來數了一下,線程數也沒有異常膨脹。
把程式執行的每一句話前後都加上日志輸出,驚訝的發現程式停在service調用dao的那個地方了。dao方法剛進去的第一句列印日志的話都不輸出。難道是程式調用還能出錯?!這個問題我現在也沒想通,估計是spring從中搞的什麼鬼。是以幹脆就把dao層拆掉,代碼都複制到service層來,結果代碼卡在資料庫查詢那一句上了。
檢視CPU和記憶體消耗都很低,但程式無故停住,這個現象和死鎖也是一樣的。但是程式中根本沒用到鎖,是以也可以排除。
想到自己是用dbcp的,上網一查說有bug的人很多,這就在想是不是考慮更新一下dbcp的版本,或者換成c3p0來試試。無奈中把資料庫配置還弄錯了,出問題的那個資料源反而沒更換成c3p0,導緻問題還是沒解決。
醒悟:
SB的事情做的太多了,居然傻到數線程數,為什麼不直接檢視程式停在哪一句呢?!當程式再次卡住的時候,果斷kill -3 [pid]把記憶體狀态列印出來,結果一看就停在dbcp的getConnection方法上了。顯然我是遇到了傳說中的dbcp的bug,這次更換的時候又發現上次配置檔案給寫錯了,悲劇啊。把dbcp更新到最新版本,運作了幾天都沒再現問題了。
kill指令隻能在linux下面用,其實也可以用jdk自帶的工具,比如用jstack去檢視線程運作情況,這樣在windows下面也可以使用。
總結:
Java是一個很開放的程式,對于出問題的情況利用提供的工具大部分都很容易定位。這中間一是你要知道有什麼樣的工具可以輔助你,至少你要把jdk/bin下面自帶的工具看一遍;另外就是要有借助工具解決問題的意識,如果還是和剛開始學寫代碼的時候就知道到處列印輸出的語句,那解決問題的層次實在是太低了,也很難把問題真正解決。
本文轉自passover 51CTO部落格,原文連結:http://blog.51cto.com/passover/551554,如需轉載請自行聯系原作者