JVM成长之路,记录一次内存溢出导致频繁FGC的问题排查及解决

现象:

现象截图:

内存:

命令: jmap -heap 30069   

GC截图: 

FGC 次数 19529 次!!!何等的恐怖!!!!!

命令: jstat -gcutil 30069 1000

(小记,排查cpu100%,top  看进程cpu, top -Hp  PID 看进程内线程cpu占用, 转成16进制,用jstack查看)

现象描述:

Node模块启动后收到请求却未能响应。 一直在频繁的FGC。新生代内存爆满。老年代内存爆满!

开始分析:

启动Xmx参数为 -Xmx 128M -Xms 128M 
初步判断内存不足,第一次修改: -Xmx 256M -Xms 256M  
=============================================
运行一两天后,Node再次未响应!!!!效果仍然不好 FGC。
=============================================
使用命令查看启动参数:jps -m -l -v
30069 jars/dubhe-node-frame-1.0.0.jar com.dtwave.dipper.dubhe.node.DubheNode --spring.profiles.active=prd -Xms256m -Xmx256m -Xmn64m
 
什么情况???
新生代大小大概是 3/8  256 * 3/8 有 120M 可是却被限制到 64M ....
 
 
Xmn只分配了64M。 一旦读日志。新生代满了就直接分配到老年代了!!
于是去掉了这个参数 给Xmn一个自由!!!
=============================================
运行一两天后,Node再次未响应!!!!
=============================================
于是。给xmx翻个倍!
第二次修改:-Xmx 512M -Xms 512M
这样新生代是3/8  170M 了。这样总没问题了吧!!
=============================================

可是。。。。。。。运行一两天后,Node再次未响应!!!!看来之前的解决方法是 错的!!错的!!错的!!

根本不是什么堆空间大小的问题。

=============================================
到底是什么情况!!!!!!!!!!!!!!!!!!!!!!!!!
那就来看看堆里面到底藏了些什么!!!
执行命令:jmap -histo 14273
  1. num #instances #bytes class name
  2. ----------------------------------------------
  3.  1: 1001750 155802576 [B
  4.  2: 137954 32307952 [C
  5.  
<think>好的,我现在需要帮助用户了解如何排查Java内存溢出问题。用户已经提供了一些参考引用,我需要结合这些资料,整理出一个清晰的步骤指南。首先,我需要回忆常见的堆内存溢出原因,比如内存泄漏、大对象分配、不合理的JVM配置等。然后,根据用户提供的引用内容,看看他们提到的排查方法有哪些。 引用[1]中提到了模拟内存溢出场景,通过循环创建大对象导致内存溢出,这可能用于复现问题。引用[2]和[4]提到了使用jstat、jconsole、jvisualvm等工具监控内存使用情况,特别是老年代和GC情况。引用[3]则涉及分析线程堆栈,查看哪个线程导致问题,并考虑Full GC无法回收的情况。需要将这些步骤有条理地组织起来。 首先,用户需要确认错误类型,是否是OutOfMemoryError: Java heap space。然后,使用内存分析工具获取堆转储文件,比如-XX:+HeapDumpOnOutOfMemoryError参数。接着,通过jstat监控GC情况,如果Full GC频繁且回收效果差,可能存在内存泄漏。分析堆转储文件,查找占内存最多的对象和其引用链,确定是否有无法释放的对象。同时,检查代码是否有内存泄漏,比如未关闭的资源、集合类缓存未清理等。 需要注意引用[3]中的例子,即使线程本身不创建大量对象,可能是之前的内存泄漏积累导致。因此,需要综合多种信息,不能仅看错误提示的线程。另外,用户可能需要调整JVM参数,比如增大堆大小,但如果是内存泄漏,这只能延缓问题,不能根本解决。 最后,生成相关问题,比如工具使用、内存泄漏定位、参数调整等,帮助用户进一步学习。确保回答结构清晰,分步骤说明,并正确引用提供的资料。</think>Java内存溢出排查可分为六个关键步骤,结合工具监控和代码分析进行定位: 一、确认错误类型 检查错误日志中是否明确出现$OutOfMemoryError: Java heap space$,这是堆内存溢出的典型特征[^1][^3] 二、配置堆转储 启动参数添加: ```java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump ``` 当OOM发生时自动生成hprof文件[^4] 三、实时监控 1. 使用jstat监控GC状态: ```bash jstat -gcutil <pid> 1000 20 # 每秒采样持续20次 ``` 观察$FGC$(Full GC次数)和$FGCT$(Full GC耗时)是否持续增长,$O$(老年代使用率)是否持续高位[^2] 2. 通过jvisualvm连接进程,查看: - 堆内存曲线变化 - 对象创建直方图 - 存活对象树状图 四、分析堆转储 使用MAT或jhat分析hprof文件: 1. 查找占用最大的对象 2. 检查支配树中的异常对象链 3. 对比多次dump文件观察对象增长趋势 五、代码审查重点 1. 静态集合缓存(如HashMap)是否未清理 2. 流资源未关闭(数据库连接、文件句柄) 3. 第三方库的内存使用模式 4. 线程局部变量积累 六、场景验证 参考创建最小复现案例: ```java // 模拟内存泄漏 List<byte[]> leakList = new ArrayList<>(); while(true) { leakList.add(new byte[1024*1024]); } ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值