报错是这么冒出来的。服务运行一段时间后报堆内存不足,日志里大量异常,重启后能撑几天,监控显示堆一直贴着上限。

原因不止一个,得分开看。堆上限设置小于业务峰值所需。还有一种是存在对象泄漏,回收后占用不下降。

不容易想到的是,一次查询把大量数据加载进内存。

动手时先确认堆上限与使用曲线

jstat -gcutil $(pidof java) 1000 5

再往下导出堆快照分析占用

jmap -dump:live,format=b,file=/data/heap.hprof $(pidof java)

然后确认常见大对象

jmap -histo:live $(pidof java) | head -20

等前面都确认过,再按物理内存调整堆上限

grep -n Xmx /opt/app/start.sh

改之前先确认了最近有没有人动过配置,避免白查一遍。

怎么算真的好了,看的是同一批现象。堆使用率稳定在七成以下,完整回收后能明显下降,不再出现内存溢出。

提醒一点。堆不是越大越好,超过物理内存会引发交换和长时间回收;先确认是泄漏还是容量不足再动手。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189