问题分析

内存泄漏是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory(OOM)那就是内存溢出。内存溢出也就是内存不够用,在测试环境没有大量用户请求的场景下基本上很难出现oom,大部分应用都是上线生产环境遇到内存溢出,java.lang.OutOfMemoryError:Java heap space问题。

问题发生

应用内存溢出,服务器基本宕机,对业务造成较大影响,从日志定位到内存泄漏很容易,但如何定位到是哪里代码造成内存泄漏,看完本篇文章相信你会有一个比较清晰的思路。

查看日志发现堆内存泄漏

java.lang.OutOfMemoryError: Java heap space
21-02-02 10:11:04.693 [DiscoveryClient-0] WARN com.netflix.discovery.TimedSupervisorTask.run - task supervisor timed out

主业务服务占用服务器2.9g内存

[root@szvmapstms01 ~]# top -b -n 1 | grep java| awk '{print "PID:"$1",mem:"$6",CPU percent:"$9"%","mem percent:"$10"%"}'
PID:52898,mem:433604,CPU percent:6.2% mem percent:5.4%
PID:52957,mem:351160,CPU percent:6.2% mem percent:4.4%
PID:15446,mem:2.9g,CPU percent:0.0% mem percent:37.7%
PID:52936,mem:534252,CPU percent:0.0% mem percent:6.7%

进入JDK的bin目录执行
./jmap -dump:format=b,file=/srv/jvmDmp.hprof 43360
参数说明 (1)file:生成dump文件的路径及文件名称 (2)43360应用的PID

查看supervisor发现启动分配堆内存2g

[program:服务名]
 command=java -jar -Dserver.port=9633-Xms512m -Xmx2048m -Xss256K -XX:MetaspaceSize=200m -XX:MaxMetaspaceSize=256m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 服务名.jar --spring.config.location=/config/application-recall.yml

修改启动参数内存泄漏时生成内存dump

[program:服务名]
 command=java -jar -Dserver.port=9633-Xms512m -Xmx2048m -Xss256K -XX:MetaspaceSize=200m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/srv/jvmDump -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 服务名.jar --spring.config.location=/config/application.yml

参数说明

(1)-XX:+HeapDumpOnOutOfMemoryError参数表示当JVM发生OOM时,自动生成DUMP文件。

(2)-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径及文件名称。

从服务器拿下来dump文件

内存溢出 Python 内存溢出排查_服务器

下载分析工具(博主这里使用的JProfiler)

1.查看class

内存溢出 Python 内存溢出排查_服务器_02


2.查看biggest object

内存溢出 Python 内存溢出排查_java_03


3.Use Slected Objects

内存溢出 Python 内存溢出排查_服务器_04


4.Incoming references

内存溢出 Python 内存溢出排查_内存泄漏_05


incoming references-显示这个对象被谁引用

outcoming references-显示这个对象引用的其他对象5.查看

内存溢出 Python 内存溢出排查_内存溢出 Python_06


ok以上已经定位到代码具体位置

查看代码

内存溢出 Python 内存溢出排查_服务器_07

结合业务分析代码

业务场景需要分段抓取大量页面元素,开发同事把大量页面元素放入redis,该方法主要用于一次性读取出来,设计方案不合理,内存消耗过高导致OOM。