YGC過于頻繁問題以及解決方案
頻繁的 Young GC(YGC)通常反映JVM年輕代內(nèi)存配置或?qū)ο蠓峙錂C制存在問題,以下是針對性排查和優(yōu)化方案:
一、快速定位瓶頸
實時監(jiān)控指標
# 每2秒采集GC數(shù)據(jù)(替換PID) jstat -gcutil <pid> 2000 # 關(guān)鍵指標解讀: - YGCT: Young GC總耗時 - YGC: Young GC次數(shù) - EU/S0/S1: Eden/Survivor區(qū)使用率
正常情況:單次YGC耗時應<50ms,1分鐘內(nèi)YGC次數(shù)<5次
GC日志分析
啟動參數(shù)追加:
-Xlog:gc*=debug:file=gc.log:time,uptime,level,tags:filecount=5,filesize=100m
使用 GCeasy 在線解析日志,重點關(guān)注:
- 對象晉升速率(Promotion Rate)
- 分配失敗觸發(fā)GC(Allocation Failure)
二、核心優(yōu)化策略
A. 內(nèi)存結(jié)構(gòu)調(diào)整
| 參數(shù) | 典型場景 | 計算公式 |
|---|---|---|
| -XX:NewRatio=3 | 老年代與年輕代比例 3:1 | NewSize=Heap/(NewRatio+1) |
| -XX:SurvivorRatio=8 | Eden與單個Survivor區(qū)比例 8:1:1 | Eden = Young/(SurvivorRatio+2) |
動態(tài)計算工具:
使用 JVM Heap Calculator 可視化調(diào)整
B. 分配速率優(yōu)化
1.對象池化
對頻繁創(chuàng)建的短生命周期對象(如DTO)采用對象池:
// 使用Apache Commons Pool
GenericObjectPool<Request> pool = new GenericObjectPool<>(new BasePooledObjectFactory<>() {
@Override public Request create() { return new Request(); }
});2.堆外內(nèi)存
對大型臨時數(shù)據(jù)使用DirectByteBuffer:
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024); // 1MB off-heap
C. 收集器專項優(yōu)化
G1調(diào)優(yōu)(推薦JDK8+)
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 # 目標停頓時間 -XX:G1NewSizePercent=30 # 年輕代最小占比 -XX:G1MaxNewSizePercent=60 # 年輕代最大占比
ZGC低延遲方案(JDK15+)
-XX:+UseZGC -XX:ZAllocationSpikeTolerance=5.0
三、異常場景處理
案例1:過早提升(Premature Promotion)
現(xiàn)象:Survivor區(qū)頻繁溢出,對象過早進入老年代
解決:
-XX:TargetSurvivorRatio=60 # 控制Survivor空間利用率 -XX:+NeverTenure # 禁止直接晉升(G1可用)
案例2:內(nèi)存泄漏
堆轉(zhuǎn)儲分析
jmap -dump:live,format=b,file=heap.bin <pid>
用MAT工具檢查Retained Heap最大的對象
弱引用監(jiān)控
WeakReference<Object> ref = new WeakReference<>(largeObj);
if (ref.get() == null) System.out.println("對象已被回收");四、終極應急方案
當無法立即修改代碼時,內(nèi)存急救措施:
# 臨時擴容年輕代(不重啟JVM) jcmd <pid> VM.set_flag -XX:NewSize=512m jcmd <pid> VM.set_flag -XX:MaxNewSize=512m # 強制啟動Full GC回收老年代(慎用) jcmd <pid> GC.run
優(yōu)化驗證流程:
- 使用 JMH 做GC壓力測試
- 對比優(yōu)化前后
jstat的YGC頻率下降比例 - 通過APM工具(Arthas)觀察業(yè)務TPS波動
通過以上方法,通常可將YGC頻率降低50%-90%。若仍存在異常,需要結(jié)合具體業(yè)務代碼進行內(nèi)存分配路徑分析。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
深入了解Spring中g(shù)etBean()的五種方式
在本文中,我們將詳細介紹從BeanFactory中獲取bean的多種方式。簡單地說,正如方法的名稱所表達的,getBean()負責從Spring?IOC容器中獲取bean實例,希望對大家有所幫助2023-02-02
SpringBoot+VUE實現(xiàn)數(shù)據(jù)表格的實戰(zhàn)
本文將使用VUE+SpringBoot+MybatisPlus,以前后端分離的形式來實現(xiàn)數(shù)據(jù)表格在前端的渲染,具有一定的參考價值,感興趣的可以了解一下2021-08-08
Spring Cloud中FeignClient實現(xiàn)文件上傳功能
這篇文章主要為大家詳細介紹了Spring Cloud中FeignClient實現(xiàn)文件上傳功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04

