JVM診斷及工具筆記(4) 使用visualvm分析JVM堆記憶體泄漏

封面圖片不要使用微信打開文章,可以使用手機/電腦瀏覽器

在這裡感謝最近一直閱讀我文章的小夥伴,如果覺得文章對你有用,可以幫忙關注轉載,需要的時候可以及時找到文章。

背景

今年Q3季度我們在推廣業務方使用Iceberg,當時為了讓不同業務線的用戶可以使用自己的hadoop帳號許可權把數據寫到他們的hadoop集市目錄,我們在Iceberg中添加了ugi,使Flink帳號代理成業務方的hadoop帳號。這次的堆記憶體泄漏就是因為我們使用ugi錯誤方式引發的。

現象

通過監控,我們發現用戶的Flink寫Iceberg任務的堆記憶體呈增長趨勢,沒多久就報堆記憶體oom了。

image-20211026203047331

定位過程

1.列印日誌及設置oom時dump堆記憶體到磁碟

clusterConf.env.java.opts=-XX:+PrintGCDetails

-XX:+PrintGCDateStamps -Xloggc:${LOG_DIRS}/gc.log -XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/tmp/${CONTAINER_ID}.dump

2.使用visualvm分析堆記憶體文件 (一定要計算對象保留大小有助於分析)

發現最多的實例竟然是Entry對象,開始去分析其引用(主要是想查找找有沒有比較大的HashMap),

image-20211026203919097

​ 如下圖好多引用都是DistributedFileSystem引用的DFSclient對象。

image-20211026205035451

搜下DFSClient對象,發現其數量有16000多個。DFSClient對象為什麼會這麼多,繼續往下跟發現其被快取到DistributedFileSystem的cache裡面。

image-20211026205302968

​ cache中具體快取使用的key如圖 scheme, authority,ugi,unique 其中unique可以忽略,在visualvm上看都是相同的,scheme及authority記錄著幾個namenode的地址,值也並不多,唯一異常的就是存在超大量的ugi對象,此時記憶體泄漏的真兇差不多找到了。

發現在改造的Iceberg支援代理用戶的程式碼中,每次調用getFs方法都要重新創建一個ugi對象。

image-20211026211556533

解決

ugi按用戶快取起來之後,cache裡面的DFSClient對象數量就符合預期了。這個任務就再也沒有發生過堆記憶體泄漏了。

image-20211026222721656