fullgc频繁的原因_系统运行缓慢,CPU 100%,以及Full GC次数过多问题的排查思路

本文介绍了系统运行缓慢、CPU 100%和Full GC次数过多问题的排查思路,包括Full GC、CPU过高、接口耗时、线程WAITING状态和死锁的分析方法。通过jstack、jstat等工具,定位代码中可能导致问题的点,如内存溢出、耗时计算、阻塞操作和死锁状态,以解决系统性能问题。

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

  • 1. Full GC次数过多
  • 2. CPU过高
  • 3. 不定期出现的接口耗时现象
  • 4. 某个线程进入WAITING状态
  • 5. 死锁
  • 6. 小结

  • 《Netty 实现原理与源码解析 —— 精品合集》
  • 《Spring 实现原理与源码解析 —— 精品合集》
  • 《MyBatis 实现原理与源码解析 —— 精品合集》
  • 《Spring MVC 实现原理与源码解析 —— 精品合集》
  • 《Spring Boot 实现原理与源码解析 —— 精品合集》
  • 《数据库实体设计合集》
  • 《Java 面试题 —— 精品合集》
  • 《Java 学习指南 —— 精品合集》

处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题。当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警。本文主要针对系统运行缓慢这一问题,提供该问题的排查思路,从而定位出问题的代码点,进而提供解决该问题的思路。

对于线上系统突然产生的运行缓慢问题,如果该问题导致线上系统不可用,那么首先需要做的就是,导出jstack和内存信息,然后重启系统,尽快保证系统的可用性。这种情况可能的原因主要有两种:

  • 代码中某个位置读取数据量较大,导致系统内存耗尽,从而导致Full GC次数过多,系统缓慢;
  • 代码中有比较耗CPU的操作,导致CPU过高,系统运行缓慢;

相对来说,这是出现频率最高的两种线上问题,而且它们会直接导致系统不可用。另外有几种情况也会导致某个功能运行缓慢,但是不至于导致系统不可用:

  • 代码某个位置有阻塞性的操作,导致该功能调用整体比较耗时,但出现是比较随机的;
  • 某个线程由于某种原因而进入WAITING状态,此时该功能整体不可用,但是无法复现;
  • 由于锁使用不当,导致多个线程进入死锁状态,从而导致系统整体比较缓慢。

对于这三种情况,通过查看CPU和系统内存情况是无法查看出具体问题的,因为它们相对来说都是具有一定阻塞性操作,CPU和系统内存使用情况都不高,但是功能却很慢。下面我们就通过查看系统日志来一步一步甄别上述几种问题。

1. Full GC次数过多

相对来说,这种情况是最容易出现的,尤其是新功能上线时。对于Full GC较多的情况,其主要有如下两个特征:

  • 线上多个线程的CPU都超过了100%,通过jstack命令可以看到这些线程主要是垃圾回收线程
  • 通过jstat命令监控GC情况,可以看到Full GC次数非常多,并且次数在不断增加。

首先我们可以使用top命令查看系统CPU的占用情况,如下是系统CPU较高的一个示例:

top - 08:31:10 up 30 min,  0 users,  load average: 0.73, 0.58, 0.34
KiB Mem:   2046460 total,  1923864 used,   122596 free,    14388 buffers
KiB Swap:  1048572 total,        0 used,  1048572 free.  1192352 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    9 root      20   0 2557160 288976  15812 S  98.0 14.1   0:42.60 java

可以看到,有一个Java程序此时CPU占用量达到了98.8%,此时我们可以复制该进程id9,并且使用如下命令查看呢该进程的各个线程运行情况:

top -Hp 9

该进程下的各个线程运行情况如下:

top - 08:31:16 up 30 min,  0 users,  load average: 0.75, 0.59, 0.35
Threads:  11 total,   1 running,  10 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.5 us,  0.6 sy,  0.0 ni, 95.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2046460 total,  1924856 used,   121604 free,    14396 buffers
KiB Swap:  1048572 total,        0 used,  1048572 free.  1192532 cached Mem

  P
<think>好的,我现在需要回答用户的问题Full GC次数过多是否会移除我的Executor,然后YARN重新分配一个Executor。首先,我需要理解用户的问题背景。用户可能在使用Apache Spark或类似的分布式计算框架,运行在YARN资源管理器上。问题涉及到JVM的垃圾回收机制(Full GC)与资源管理(YARN)之间的交互。 首先,我应该回顾一下Full GC对应用程序的影响。Full GC会暂停应用程序线程(STW),导致延迟。如果Full GC频繁发生,说明内存回收存在问题,可能因为内存不足或对象生命周期管理不当。频繁Full GC会导致应用程序响应变慢,甚至长间停顿,这可能被集群管理器误认为节点无响应。 接下来,需要了解YARN如何管理Executor的生命周期。YARN作为资源管理器,负责启动和监控容器(包括Executor)。如果Executor进程异常退出或无法响应心跳,YARN会将其标记为失败并尝试重新分配。但Full GC本身是否会导致YARN主动移除Executor呢? 可能的机制是:频繁Full GC导致Executor进程的停顿间过长,无法及向YARN发送心跳信号。YARN的心跳机制有超设置,如果超过一定间未收到心跳,YARN会认为该Executor失效,从而终止容器并重新分配。此外,如果Full GC导致Executor进程内存溢出(OOM),进程崩溃,YARN自然也会重新启动。 需要注意的关键点包括: 1. YARN的心跳超间配置,如yarn.nm.liveness-monitor.expiry-interval-ms,默认是10分钟。如果Full GC导致Executor在这段间内无法发送心跳,YARN会将其标记为死亡。 2. JVM的OOM错误,如果Full GC后仍然无法释放足够内存,会抛出OOM,导致Executor进程退出,触发YARN重新分配。 3. Spark自身的配置,如spark.executor.extraJavaOptions中的GC相关参数,可能影响Full GC的频率和持续间。 需要验证这些机制是否正确,例如查看YARN和Spark的官方文档,确认心跳机制和容器失效的条件。此外,用户可能需要检查日志,确认Executor退出的原因是否是OOM或心跳超。 总结回答结构:先说明Full GC次数过多的影响,解释YARN如何监控Executor,分析Full GC导致移除的可能原因(心跳超或OOM),最后给出调优建议。</think>### 🚨 **核心结论** **会!频繁Full GC可能导致YARN主动移除Executor并重新分配**,主要触发机制是**心跳超检测**或**OOM崩溃**。 --- ### 📉 **根本原因分析** #### **场景1:心跳超(更常见)** - **YARN监控机制**: - NodeManager周期性(默认1秒)检测Executor进程心跳 - 连续丢失心跳超过 `yarn.nm.liveness-monitor.expiry-interval-ms`(默认600,000ms=10分钟)→ **标记为死亡** - **Full GC影响**: - 单次Full GC可能导致**分钟级STW停顿**(如CMS/G1混合GC失败) - 若10分钟内发生多次Full GC → **累计心跳超** → YARN强制kill容器 #### **场景2:OOM崩溃(直接致命)** - Full GC后仍无法释放足够内存 → 抛出 `java.lang.OutOfMemoryError: Java heap space` - Executor进程异常退出 → YARN立即重新分配新容器 --- ### 🔍 **典型日志证据** ```log // 心跳超引发的移除 WARN org.apache.hadoop.yarn.server.nodemanager.containermanager.ContainerManagerImpl: Container container_xxxx exited with status 143 (被主动终止) // OOM引发的崩溃 ERROR org.apache.spark.executor.Executor: Exception in task java.lang.OutOfMemoryError: Java heap space ``` --- ### ⚙️ **调优关键参数** #### **防御Full GC** | 参数 | 作用 | 推荐值示例 | |----------------------------------------|-----------------------------|-------------------| | `-XX:+UseG1GC` | 启用低停顿G1回收器 | 必选 | | `-XX:InitiatingHeapOccupancyPercent=35`| 提前触发GC避免堆占满 | 35~45(根据负载调整) | | `-XX:G1ReservePercent=15` | 预留内存防晋升失败 | 10~20 | #### **缓解YARN误杀** | 参数 | 作用 | 推荐值 | |-------------------------------------------|-----------------------------|------------| | `yarn.nm.liveness-monitor.expiry-interval-ms` | 心跳超阈值 | 1200000(20分钟) | | `spark.executor.heartbeatInterval` | Executor心跳间隔 | 10s → 5s | --- ### 🌰 **真实案例** 某电商实推荐系统出现Executor频繁被YARN重启: - **现象**:每小发生3~4次Executor重新分配 - **排查**: 1. GC日志显示老年代每小Full GC 15次 2. YARN日志显示 `CONTAINER_KILLED_ON_EXCESSIVE_GC` - **解决方案**: ```bash # 调整G1参数减少Full GC --conf spark.executor.extraJavaOptions="-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1ReservePercent=20" # 放宽YARN GC判定 <property> <name>yarn.nm.container-monitor.resource-calculator.class</name> <value>org.apache.hadoop.yarn.util.LinuxResourceCalculator</value> </property> <property> <name>yarn.nm.container-monitor.procfs-tree.smaps-based-rss.enabled</name> <value>false</value> </property> ``` --- ### 📌 **行动清单** 1. **优先减少Full GC**: - 分析堆转储(`jmap -histo`)查找内存泄漏 - 升级G1/CMS以外的低延迟GC(如ZGC/Shenandoah) 2. **次优调整超阈值**: ```xml <!-- yarn-site.xml --> <property> <name>yarn.nm.liveness-monitor.expiry-interval-ms</name> <value>1200000</value> </property> ``` 3. **终极方案**: - 若业务允许,直接增加Executor内存(`spark.executor.memory=8g → 12g`) - 拆分大任务避免单个Executor负载过高 --- **最终结论**:Full GC是Executor被YARN杀死的**间接推手**,本质上需要优化JVM GC或调整YARN/Spark的敏感性参数! 🔧
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值