记1次生产环境java进程内存泄漏问题定位(使用Arthas)

时间:2025-03-19 21:59:35

Arthas(阿尔萨斯)

简介 | arthas, Alibaba 开源的 Java 诊断工具,参照文档安装使用很简单,在线下载或者离线下载后解压运行,启动,会自动扫描jps进程,根据序号选择后进入arthas界面:

tar -zxvf 
cd arthas
yum install -y java
yum install -y java-1.8.0-openjdk-devel
java -jar 

java -jar 
* [1]: 105241
  [2]: 454265 

常用的是dashboard,thread命令,dashboard命令能扫面当前java进程的全局信息,包括堆栈和线程信息,

dashboard的第二个显示框Memory动态地详细展示了当前jar包的堆内存heap,非堆内存nonheap,代码缓存区code_cache,元数据空间metaspace等信息,其中heap堆内存的total总量是XMS设置的大小,除非不够用还会跟系统申请,但区间就是[Xms,Xmx],堆内存的总数+非堆内存总数+代码缓存区+元数据空间+压缩的class空间就可以理解成是占用的系统的t最小内存了,但系统内存占用肯定不止这么少;

其中第一列展示的是总堆内存的大小和占用比例,其下又分为3个区域:EC,OC,S1C,分别是新生代总空间,老年代总空间,S1总空间,EU,OU,S1U,新生代使用空间,老年代使用空间,S1使用空间,三者之和可以理解成已经使用的总的从系统那里申请的内存,arthas都会展示这个usage,

Memory    used   total   max   usage   GC 

head         248m  512m 512m 50%

 上面这个可以看出最大的head=total值,说明Xms和Xmx设置的是一样的,也就是jar包启动后就像内存申请了这么大的空间,如果两者不等,这个toal可能是介于Xms和Xmx之间的某个值的;

thread命令则是更详细的线程信息,thread命令罗列所有线程的基本信息,thread -tid,tid指的是线程id可以更详细看线程目前状态;

问题描述

生产环境中的单体应用,其运行内存达到5G,远大于jar启动时候指定的最大堆内存(512M)+非堆内存+其他,使用命令行:

# 单位是M
ps -aux |grep  |grep -v grep| awk '{total+=$6}; END {print total/1000}'

发现其占用内存的数值还在持续增长中,使用jstat命令查看其堆栈信息发现并没有频繁FGC,而且新生代和老年带分布正常,所以结论就是堆外内存溢出:

# 查看进程号
jps
# 查看 43063进程的gc情况,2s一次,打印5次 
jstat -gc 43063 2000 5

# EC,OC,S1C,分别是新生代总空间,老年代总空间,S1总空间
# EU,OU,S1U,新生代使用空间,老年代使用空间,S1使用空间
# YGC FGC分别是young gc和full gc的次数,fgc越小说明越稳定
# YGCT FGCT 分别是young gc和 full gc花费的时间
# MC MU是 metaspace空间,如果长期占用说明这个jar包经常使用反射和代理经常访问class的元数据信息
# jstat信息都可以通过arthas查看

该情况下可以查看进程启动的线程数,使用jstack查看该进程的线程数达到了10万+,且使用的线程方式是线程池的报错,那么问题绝大部分可能就是线程的启动占用了系统内存,造成内存泄漏;

# 查看43063进程启动的线程数
jstack -l 43063

使用arthas的thread命令查看线程池报错信息发现线程池的调度方式是:LinkedBlockingQueue,找到代码中的调度方式发现,该线程池在定时任务中,每过3分钟启动1个该线程池,活跃线程数是10;

解决办法

将该线程池改为全局的对象,被bean持有,定时任务每次拿到同1个线程池,而不是每次创建新的线程池,修改后问题修复;

JAR包相关jvm建议

1、Xms和Xmx设置一样大,让jar包在启动就能申请到最大的内存空间,减少jar包的oom概率,也防止后续不能申请到最大的内存,否则jar包会先申请Xms的内存空间,根据需要再申请;

2、垃圾回收器指定为G1GC,命令: -XX:+UseG1GC 

3、使用jdk自带工具进行jar的jvm分析:

jstat(jar stattistics monitoring tool),java统计信息监视恐惧,可以动态查看jvm的堆栈信息状态:jstat -gc pid 2000 5;

jstack(java stack trace tool),java堆栈分析工具,用于生产java应用程序的线程信息,jstack -l pid >,arthas的thread命令同样可以查看线程信息;

jhat(java heap analysis tool),java堆分析工具,使用arthas的headdump 可以导出,然后jhat查看,在web的7000端口可视化展示,能方便地找到异常的大对象;