線上java內存泄露處理實錄1

線上現象(各類監控數據)

1.公司項目在監控平臺上開始報警(jvm堆內存佔用報警,FullGC次數超頻率報警) spring

jvm內存泄露 bob
2.觀察具體的監控圖標(預發機器) 線程數平穩(260左右)
jvm內存泄露 bob
jvm內存泄露 bob
jvm內存泄露 bob
jvm內存泄露 bob
3. 方法監控能夠看到在fullGC比較頻繁時,業務方法幾乎無響應
jvm內存泄露 bob

線上配置(jvm配置,運行時內存分佈)

  1. 項目版本:jdk8 ,spring 5, 默認垃圾處理器 Parallel GC with 43 thread(s) -Xms800m -Xmx800m -XX:MaxPermSize=256m
    jvm內存泄露 bob
    2.運行時jstat
    jvm內存泄露 bob
    3.運行時jmap histo
    jvm內存泄露 bob
    4.heap
    jvm內存泄露 bob
    5.dump文件1G左右,不發了,稍後看一下MAT分析的圖表吧

邏輯分析(定位問題大體方向)

1.經過監控和運行時數據分析,堆內存(年輕代和老年代)、非堆(方法區)、均打滿配置內存 2.即便FullGC,堆內存和非堆也只能回收少量內存,而且總體水位傾斜向上,直到內存溢出jvm

經過邏輯分析,內存溢出問題來自於存在泄漏,接下來分析dump文件工具

內存分析(定位問題確切泄漏源)

採用MAT工具載入dump文件進行leak分析 性能

jvm內存泄露 bob
jvm內存泄露 bob
經過分析能夠看出紅色的業務方法保留引用太多, 找到泄漏源了,接下來就分析業務代碼具體的問題

代碼分析(定位致使泄露代碼片斷)

jvm內存泄露 bob
jvm內存泄露 bob
經過分析,咱們最終定位了這段代碼,咱們改造過程當中引入了一個開源的屬性運行時拷貝的包 可是咱們每次轉換的時候都會先register一遍轉換代理類,而此類底層爲每次register註冊一個新生的代理類被加載到非堆 可是又被業務代碼中的MAPPER_FACTORY引用,致使每次生成的實例充斥着年輕代又到老年代

最終的現象就是老年代、年輕代、非堆內存同時爆滿,而又GC不掉,內存泄露直到溢出線程

代碼處理

找到了具體的代碼問題,咱們將同一個類轉換的register在系統啓動時注入一次就行,不用每次調用註冊,這樣的話就不會頻繁建立和加載,就能夠解決上述問題3d

本地驗證

本地驗證錯誤使用代碼,能夠復現問題 代理

jvm內存泄露 bob
jvm內存泄露 bob
jvm內存泄露 bob
加入 參數-verbose -verbose:gc 也 能夠看到新增的代理類在循環中瘋狂生成與加載, 修復後本地監控數據平穩運行,具體圖標參考預發驗證圖表

預發驗證

jvm內存泄露 bob
jvm內存泄露 bob
jvm內存泄露 bob
jvm內存泄露 bob
預發驗證後續咱們還將採用壓測排除性能與其餘內存問題,這次排除結束。

後記

這次問題仍是屬於比較常見的內存溢出分析,總體按着經常使用流程沒有太多的難點,只有在分析register的時候一時定位不到是開源包的register方法調用的緣由(雖然過後感受很簡單,當時也是耗費了30分鐘左右才發現)。cdn

troube shooting 三要素: 鍛鍊本身的邏輯思惟、鍛鍊本身的技術能力、多看多查blog

相關文章
相關標籤/搜索