根據堆棧日誌定位內存泄漏

【問題描述】:服務後端是3節點集羣,凌晨出現2節點磁盤打滿告警並致使業務中斷,定位發現是jvm堆棧日誌hprof,該文件比較大(大概10G+)。恢復線上業務後,恰好另外一節點磁盤沒有滿,並打出堆棧日誌,能夠用來定位這次故障緣由。linux

工具:MemoryAnalyzer-1.8.1.20180910-win32.win32.x86_64後端

tomcat bin/setenv.sh配置堆棧日誌:tomcat

export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
export CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=/opt/admin/logs/CloudNetmonitor-Computer"安全

【定位過程】:服務器

第一步 從線上導出堆棧日誌到本地分析網絡

   因爲公司安全策略,線上與本地網絡隔離,須要堡壘機傳送文件而且限制大小,在linux服務器上須要拆分日誌文件:jvm

   拆包: tar czf - sourcefile | split -b 90m - dest_split.工具

   合併:cat dest_split.* >> dest.tar.gz線程

   解包:tar zxvf dest.tar.gz日誌

第二步 啓動MAT工具

   啓動前配置MemoryAnalyzer文件,調大內存 -Xmx12g

   MAT工具 File- Open Head Dump 導入hprof文件,大文件可能持續一段時間,導入後

  

第三步 分析內存泄漏

首先根據 餅狀圖能夠直觀的發現,有內存泄漏9.7G,點擊 leak suspecks 能夠查看可疑泄漏位置,點擊查看詳細,可發現是RedisListenerPool這個類中定義的 固定線程池引用變量堆內存過大。

 

MAT工具提供的分析仍是比較全面,查看「Accumulated Objects in Dominator Tree」,發現是線程池隊列長度打滿,並且該隊列是個鏈表阻塞隊列,轉到對應代碼位置

 

問題代碼位置:

private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);

查看固定線程池源碼:

    找到問題了,這裏默認定義的是不指定容量大小的阻塞隊列,意味着是無限大小。做爲開發者,咱們須要注意的是,若是構造一個LinkedBlockingQueue對象,而沒有指定其容量大小,LinkedBlockingQueue會默認一個相似無限大小的容量(Integer.MAX_VALUE),這樣的話,若是生產者的速度一旦大於消費者的速度,也許尚未等到隊列滿阻塞產生,系統內存就有可能已被消耗殆盡了。

相關文章
相關標籤/搜索