頻繁full gc會導致
1. 機器 cpu 負載過高
2. 頻繁 full gc 告警
3. 系統無法請求處理或者過慢, 接口無關 全面性的
出現以上異常的時候,要第一時間反應過來可能是 full gc的問題
頻繁full gc的常見原因
full gc 觸發條件是 老年代空間不足, 所以追因的方向就是導致 老年代空間不足的原因:
大量對象頻繁進入老年代 + 老年代空間釋放不掉
- 系統並發高、執行耗時過長,或者數據量過大,導致 young gc頻繁,且gc后存活對象太多,但是survivor 區存放不下(太小 或 動態年齡判斷) 導致對象快速進入老年代 老年代迅速堆滿
- 發程序一次性加載過多對象到內存 (大對象),導致頻繁有大對象進入老年代 造成full gc
- 存在內存溢出的情況,老年代駐留了大量釋放不掉的對象, 只要有一點點對象進入老年代 就達到 full gc的水位了
- 元數據區加載了太多類 ,滿了 也會發生 full gc
- 堆外內存 direct buffer memory 使用不當導致
- 也許, 你看到老年代內存不高 重啟也沒用 還在頻繁發生full gc, 那么可能有人作妖,在代碼里搞執行了 System.gc();
定位思路
如果有監控,那么通過圖形能比較直觀、快速的了解gc情況;
如果沒有監控,那么只能看gc日志或jstat來分析 這是基本技能 一定要熟練
- 觀察年輕代 gc的情況,多久執行一次、每次gc后存活對象有多少 survivor區多大
存活對象比較多 超過survivor區大小或觸發動態年齡判斷 => 調整內存分配比例 - 觀察老年代的內存情況 水位情況,多久執行一次、執行耗時多少、回收掉多少內存
如果在持續的上漲,而且full gc后回收效果不好,那么很有可能是內存溢出了 => dump 排查具體是什么玩意 - 如果年輕代和老年代的內存都比較低,而且頻率低 那么又可能是元數據區加載太多東西了
- 其實如果是自己負責的系統,可能要看是不是發版改了什么配置、代碼