(转)一次让人难以忘怀的排查频繁Full GC过程

本文分享了如何解决Java应用因频繁FULLGC导致性能下降的问题。通过调整JVM参数Xms与Xmx保持一致,避免Java堆内存不足引起的频繁FULLGC,并禁用System.gc调用来减少FULLGC触发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 我们的Java应用因频繁FULL GC导致性能降低很多,经过多人的定位也没有结论,于是我自主请命,经过一天的研究终于搞定了,现把经验与大家共享,相关的gc日志如下:

4.758: [Full GC [PSYoungGen: 464K->0K(71936K)] [PSOldGen: 37949K->33994K(68672K)] 38413K->33994K(140608K) [PSPermGen: 33221K->33221K(66560K)], 0.1887540 secs] [Times: user=0.20 sys=0.00, real=0.19 secs]

32.324: [Full GC [PSYoungGen: 12025K->0K(176320K)] [PSOldGen: 57570K->65642K(128256K)] 69595K->65642K(304576K) [PSPermGen: 35548K->35548K(76544K)], 0.2467320 secs] [Times: user=0.22 sys=0.02, real=0.25 secs]

50.133: [Full GC [PSYoungGen: 20999K->0K(437248K)] [PSOldGen: 118647K->114524K(198528K)] 139647K->114524K(635776K) [PSPermGen: 49637K->49637K(84224K)], 0.3302180 secs] [Times: user=0.32 sys=0.00, real=0.33 secs]

149.586: [Full GC [PSYoungGen: 44223K->0K(411712K)] [PSOldGen: 190278K->185382K(296064K)] 234501K->185382K(707776K) [PSPermGen: 50674K->50208K(85248K)], 0.6151800 secs] [Times: user=0.62 sys=0.00, real=0.61 secs]

260446.223: [Full GC [PSYoungGen: 31393K->0K(436032K)] [PSOldGen: 1006486K->396428K(1021312K)] 1037880K->396428K(1457344K) [PSPermGen: 61093K->61093K(61440K)], 1.3636610 secs] [Times: user=1.36 sys=0.00, real=1.52 secs]

260630.161: [Full GC (System) [PSYoungGen: 40410K->0K(424768K)] [PSOldGen: 991397K->721859K(1021312K)] 1031808K->721859K(1446080K) [PSPermGen: 61100K->61100K(61440K)], 2.1272130 secs] [Times: user=2.14 sys=0.00, real=2.13 secs]

260720.146: [Full GC (System) [PSYoungGen: 4949K->0K(439360K)] [PSOldGen: 1004066K->833610K(1021312K)] 1009015K->833610K(1460672K) [PSPermGen: 61108K->61108K(61440K)], 2.8408660 secs] [Times: user=2.72 sys=0.10, real=2.84 secs]

260810.150: [Full GC (System) [PSYoungGen: 33459K->0K(463552K)] [PSOldGen: 949989K->245655K(1021312K)] 983448K->245655K(1484864K) [PSPermGen: 61117K->61088K(61184K)], 1.1344010 secs] [Times: user=1.12 sys=0.02, real=1.14 secs]

03430.144: [Full GC (System) [PSYoungGen: 7390K->0K(489024K)] [PSOldGen: 871871K->393481K(976704K)] 879262K->393481K(1465728K) [PSPermGen: 64306K->64295K(64640K)], 1.3848850 secs] [Times: user=1.34 sys=0.06, real=1.38 secs]

403794.982: [Full GC [PSYoungGen: 9352K->0K(454144K)] [PSOldGen: 963758K->426051K(991744K)] 973110K->426051K(1445888K) [PSPermGen: 64298K->64298K(64640K)], 1.3783510 secs] [Times: user=1.32 sys=0.06, real=1.38 secs]

404120.149: [Full GC (System) [PSYoungGen: 6846K->0K(467648K)] [PSOldGen: 943642K->440168K(991744K)] 950489K->440168K(1459392K) [PSPermGen: 64300K->64300K(64640K)], 1.1605070 secs] [Times: user=1.12 sys=0.04, real=1.16 secs]

404466.698: [Full GC [PSYoungGen: 9719K->0K(472768K)] [PSOldGen: 980355K->442899K(1021312K)] 990074K->442899K(1494080K) [PSPermGen: 64303K->64303K(64640K)], 1.1729280 secs] [Times: user=1.14 sys=0.04, real=1.18 secs]

 

经过日志分析,我找到两个突破点,重点关注红色字体部分的日志,分析过程如下: 

1)FULL GC前后Java堆大小有变化;经研究发现是由于Java应用JVM参数XMS设置为默认值,在我们的系统环境下,Hotspot的Xms默认值为50M(-Xms默认是物理内存的1/64);每次GC时,JVM会根据各种条件调节Java堆的大小,Java堆的取值范围为[Xms, Xmx]。根据以上分析,修改Xms值与Xmx相等,这样就不会因为所使用的Java堆不够用而进行调节,经过测试后发现FULL GC次数从四位数减少至个位数。


2)关键词“System”让我想到了System.gc调用,System.gc调用只是建议JVM执行年老代GC,而年老代GC触发FULL GC,JVM会根据系统条件决定是否执行FULL GC,正因为系统条件不好判断,所以很难构造System.gc调用触发FULL GC,几经周折终于成功,当System.gc触发FULL  GC时都会有关键词“(System)”,而 JVM自动触发的FULL GC却不带关键词“(System)”,可以断定是Java应用存在“System.gc”代码。经过本次测试我也发现System.gc的真正含义,通俗言之,“System.gc” 就是FULL GC触发的最后一根稻草。 

从本次分析中,我们可以得出如下的经验: 
1)Java应用的jvm参数Xms与Xmx保持一致,避免因所使用的Java堆内存不够导致频繁full gc以及full gc中因动态调节Java堆大小而耗费延长其周期。 

2)建议不要调用System.gc或者Runtime.getRuntime().gc,否则本次调用可能会成为“压死骆驼的最后一根稻草”。当然我们可以通过设置jvm参数禁止这种调用生效,但是除非特别有把握该参数有必要添加,否则不推荐这么设置。

https://my.oschina.net/goldwave/blog/168515

以下是基于MM32G0001单片机的一个简单示例代码,它可以让LED每秒闪烁一次。假设我们使用的是GPIO端口上的某个引脚来控制LED的状态切换。 ### 示例代码 ```c #include "reg_mm32.h" // 延迟函数实现大约一秒的时间延迟 void delay_1s(void){ volatile uint32_t i,j; for(i=0;i<48000;i++) // 调整这个循环次数可以改变延时长度,这里假定系统频率为6MHz左右 for(j=0;j<950;j++); } int main(void) { // 配置RCC时钟以启用PORTA GPIO外设 RCC->PERIPHCLOCKEN |= RCC_PERIPHCLOCKEN_IOPA; // 设置PORTA第5位作为输出模式推挽驱动能力最大电流限制下工作(PUSH-PULL OUTPUT MODE) IOCFG->IOFEN &= ~(1<<5); IOCFG->IODIR |= (1<<5); while(1){ // LED亮起状态处理部分 IODATA->OUTSET = (1<<5); delay_1s(); // 灭灯操作相应段落描述 IODATA->OUTCLR = (1<<5); delay_1s(); } } ``` 上述程序首先设置了PA5针脚为通用输出用途并持续在一个无限循环里反复地将该管脚高低电平换以此达成周期性的点亮熄灭外部连接的小型发光二极管元件目标动作节奏维持在约莫每隔千毫秒即一秒钟交替一次之间流往复不已直至电源切断为止方休止运作流程终止结束全部进程任务告一段落归于平静不再继续下去了结所有事情回归初始状况停止一切活动静默无声息般消逝不见踪影无迹可寻仿佛从未存在过一般彻底湮没消失殆尽成为历史尘埃的一部分永垂不朽长存记忆深处永远铭刻心中难以忘怀追忆缅怀不舍离去久久不愿散去挥之不去萦绕心头缠绵悱恻情感深厚浓郁炽烈滚烫炙热难耐渴望重温旧梦再度经历昔日美好时光重现眼前栩栩如生历历在目恍若昨日清晰可见触手可及近在咫尺天涯咫尺间遥相呼应彼此牵连互相吸引产生共鸣形成共振效应激荡起伏澎湃汹涌气势磅礴震撼心灵魂深处最柔软地方触动内心弦音袅袅余韵悠扬飘逸轻灵洒脱自在逍遥随心所欲无所羁绊束缚拘束自由驰骋翱翔天地广阔任君纵横捭阖施展才华技艺创造奇迹辉煌成就伟业名留青史流芳百世万代敬仰膜拜朝圣礼拜顶礼赞叹歌颂赞美称许嘉奖褒扬赞誉不断……
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值