記一次業(yè)務(wù)線使用db連接中間件造成的Full GC

????業(yè)務(wù)線最近有個應(yīng)用,過不了十幾天就會開始瘋狂的Full GC,發(fā)生了兩次了,業(yè)務(wù)線對業(yè)務(wù)dump后,發(fā)過來截圖,說是qclient中的對象導(dǎo)致內(nèi)存爆了。

????qclient是我們這邊分庫分表的中間層,遵循了JDBC規(guī)范實現(xiàn)。

????首先確定是否如業(yè)務(wù)線所說,用jmap -dump:format=b,file=/tmp/dump.jprof,用工具打開后,發(fā)現(xiàn)確實如期所說。那就開始看相關(guān)的代碼。

????首先看這幾類相關(guān)的源碼,QConfigExtractorLoader應(yīng)該是這幾類的入口,問題應(yīng)該出在這個類上。


????每次調(diào)用這個類的init時,靜態(tài)屬性store會將相關(guān)的runnable匿名類,增加到callbacks中,而這個callbacks是個CopyOnWriteArrayList,這個加入的callback一直有l(wèi)ist指向,導(dǎo)致引用一直存在,導(dǎo)致gc不能將其清理掉。找到可能的原因,那么是誰調(diào)用了這么多次init方法了?


????查看了所有代碼,這個類的new就只有AdaptiveConfigLoader去反射調(diào)用,那么AdaptiveConfigLoader就是整個可能的入口,那又是什么調(diào)用了這么多次了?

????查看AdaptiveConfigLoader的實例化的地方,一共有9個方法,向上肯幾層的話,會發(fā)現(xiàn)都是在PostConstruct注解里面初始化的,而這幾個類的bean應(yīng)該是不會一直初始化的,問題定位陷入了胡同。感覺應(yīng)該不是我們的中間件有問題,可能是業(yè)務(wù)線使用我們中間件的問題。

????那就開始查業(yè)務(wù)線的機(jī)器日志,我的天,那日志看起來就不是給人看的。。。。打印的完全沒有一點(diǎn)邏輯,時間線15點(diǎn)有,3點(diǎn)pm也有。。。warn事件也不打印,就打印info日志,debug日志,error日志,日志的信息也完全沒有有用的信息,偏偏中間件的很多和這個相關(guān)的都是warn日志,從日志下手算是失敗了。

????那就jstack看線程棧吧,線程棧倒是有兩個線程有關(guān)鍵字qclient,但都是sleep的狀態(tài),而且看代碼,是個一分鐘的任務(wù),也不會創(chuàng)建和這個相關(guān)的實例。那這些實例是從哪來的,創(chuàng)建了這么多實例,線程棧應(yīng)該是有關(guān)鍵字qclient去創(chuàng)建它的地方。

????使用我們的工具集開始查問題,開啟定時jstack和定時的統(tǒng)計實例個數(shù)(底層使用java的agent進(jìn)程的java代碼調(diào)用tools下的類,沒有新開進(jìn)程,比較輕量級),統(tǒng)計五分鐘后發(fā)現(xiàn)一個比較有意思的地方,相關(guān)實例每分鐘加60個,到這就可以看出問題了,應(yīng)該是個定時任務(wù),每秒加一個實例。

????就應(yīng)該不是中間件自身的問題了,在AdaptiveConfigLoader實例化的地方加個斷點(diǎn),果不其然,斷點(diǎn)馬上觸發(fā)斷點(diǎn),看調(diào)用棧,是個定時任務(wù)線程池相關(guān)的棧,還看到業(yè)務(wù)線的代碼package的開頭,和業(yè)務(wù)線確認(rèn),問題找到了。

業(yè)務(wù)線自身的問題,反射的調(diào)用datasource的map,但是這個反射操作會增加callback,所以一秒加一個,15、6天正好加個100多萬個。

問題解決。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容