1. 程式人生 > >一次頻繁Full GC的排查過程

一次頻繁Full GC的排查過程

問題描述
最近公司的線上監控系統給我推送了一些kafka lag持續增長的訊息,我上生產環境去看了相應的consumer的情況,發現幾臺機器雖然還在處理訊息,但是速度明顯慢了很多。

問題猜測與驗證
我猜測是JVM頻繁做Full GC,導致程序也跟著頻繁卡頓,處理訊息的速度自然就慢了。為了驗證這個想法,先用jstat看看記憶體使用情況:

jstat -gcutil 1 1000 #1是程序號

結果如我所料,幾乎1秒鐘就要做一次FGC,能安安靜靜的做個正常的consumer才有鬼了。

趕緊留了一臺consumer拿來做分析,把別的幾臺consumer都重啟。不管怎樣,先恢復消費能力再說!

記憶體洩露root cause排查
1秒一次FGC,那肯定是發生記憶體洩露了。

二話不說,把堆dump下來先!

jmap -F -dump:format=b,file=heapDump 1 #1是程序號

生成的heapDump檔案有將近2個G的大小,這麼大個檔案,為了不影響生產環境的機器,還是scp到本地進行分析吧!

jhat了一下,直接卡在那裡不動了。沒辦法,祭出VisualVM來幫忙。匯入檔案之後,發現有一大堆HashMap的Node在那佔著:

然而並不知道這是個啥,點進去看看內容,發現有一大堆node的key型別是X509CertImpl:

這時候我意識到,問題可能出在網路連線上面。但是還是沒法定位到具體的程式碼。

沒辦法,接著向上找線索。不斷地通過OQL查詢Referrers:

接著查詢:

接著查詢:

這時候看到了連線池的蹤跡,感覺離真相不遠了! 


到了這裡,我心裡大概知道了答案:問題一定出在阿里雲OSS身上。再結合這張圖:

就可以猜出是因為使用了OSS的客戶端,但是沒有正確的釋放資源,導致client被回收時,它所建立的資源因為還有別的referrer, 卻沒有被回收。

再去oss github上的sample一看,果然有這麼一段:

而這個shutdown方法做的正是釋放Idle資源的事兒:

public void shutdown() {
        IdleConnectionReaper.removeConnectionManager(this.connectionManager);
        this.connectionManager.shutdown();
 }
1
2
3
4
問題修復
知道了原因,修復也是很輕鬆的事兒。 在建立client的快取里加個removeListener,用來主動呼叫client.shutdown(), 美滋滋:


--------------------- 
作者:沈鴻斌 
來源:CSDN 
原文:https://blog.csdn.net/u012422829/article/details/78154495 
版權宣告:本文為博主原創文章,轉載請