排查java应用linux环境内存占用过高的问题

一、问题场景

在一个短信平台的项目中,设置了一个下发节点的Xmx为16G,但是出现了内存撑满,导致CPU过高的情况。当时的具体情况是,该应用内存占用16G,该应用CPU占用1400%(16核),服务器负载15左右。进入应用的实时日志,发现日志每打印四五秒后,会暂停一分多钟。这代表着由于内存耗尽,导致cpu高负载,最终导致应用程序不能正常运行,断断续续。严重影响生产环境的运行速率。

二、解决方案

1、线上救急的临时方案:

(1)让运营停止审核,即停止继续往堵塞应用中送数据。

内存队列中的数据让它慢慢下放,经过几个小时的下放后,断断续续由每次四五秒到十几秒最终到几十秒,当内存队列中的数据全部清空后,断断续续仍然存在,但是要好了很多,基本是正常半分钟,暂停半分钟。这时候内存占用仍然没有明显的下降。

(2)重启服务,内存当即释放掉,所有问题得到了临时解决。
(3)将应用的Xmx由16G调高到52G,服务器是64G内存的。
(4)时刻关注这台服务器的内存cpu占用,每晚凌晨重启。

2、解决根本问题,有参考 https://www.javazhiyin.com/34154.html

(1)输入命令:top -c,查看占用内存过高的进程信息
(2)输入命令:jmap -histo:live PID > xxx.log,vim查看内存中的存活对象统计,找出业务相关的类名
(3)如果第(2)步仍然不能定位到代码中的具体对象,输入命令:jmap -dump:live,format=b,file=xxx.hprof PID

这个命令会将内存里的所有信息都输出,生成hprof文件。我16G的内存占用,输出的文件大小为1.6G。注意:这个命令会导致应用暂时挂起,所以谨慎使用。我的应用当时挂起了约10s。

(4)文件大小不是很大的话,使用jdk自带的jhat命令即可,输入命令:jhat -J-mx2G -port 7170,该命令可以查看内存占用的对象
(5)如果文件太大,可以下载到本地使用jdk自带的 jvisualvm 工具进行分析。下面详细讲怎么使用jvisualvm定位内存占用问题。

二、使用jvisualvm定位内存占用问题

1、jvisualvm.exe的文件路径在java安装路径的bin目录下

我的是 C:\Program Files\Java\jdk1.8.0_60\bin

2、打开储存堆信息的 hprof 文件

(1)注意图中 文件类型 选择【堆 Dump(。hprof,.*)】,否则hprof文件不会显示

image.png

(2)设置jvisualVM的启动堆内存

在使用 jvisualVM 的时候,加载1.6G的 hprof 文件,提示内存不足,然后中断。原来 jvisualVM 也需要设置java堆内存,于是修改Java_home/lib/visualvm/etc/visualvm.conf 文件中 visualvm_default_options="-J-client -J-Xms24 -J-Xmx256m",把256调大,本案例中设置成了1024m,然后重启jvisualVM即可


image.png

3、如果有内存泄漏,概要界面会显示它的线程,

本案例中不存在内存泄漏问题


image.png

4、进入界面具体分析

(1)如图,点击【类】,可以看到占用 内存较多的对象。

如果有应用代码中的对象,那么就破案了。此案例中 TbKeywordBan占用较高,但是应该不是主因。


image.png
(2)我们分别双击点开占用内存很多的 HashMap$Node、AtomicInteger、Long。观察引用他们的父级对象。

多点开几个进行观察,都发现了 ExpiryMap 这个类,到此处,就已经破案了。


image.png

5、找到业务代码中的 ExpiryMap.java,分析它的内存占用情况,进行java代码层面的调优工作。

你可能感兴趣的:(排查java应用linux环境内存占用过高的问题)