如何排查内存泄漏

/ jvm / 80浏览

背景

向Flink提交任务后,Flink集群下的TaskManager经常出现内存溢出问题。

工具

JProfiler

JProfiler号称最强大的内存检测工具,但是作为新手,基本不咋会使用,耗费了大半天,也只能看个大概。且监控远端时,需要在远端也装好JProfiler。

jvisualvm

java自带的一个内存检测工具,使用方便,基本功能都有。远程监控也不需要安装特殊的工具。

jcmd

jcmd也是java自带的一个工具,它可以看到内存的一个详细情况。

jvisualvm使用

远程监控配置

打开jvisualvm,点击远程,可以添加远端java进程。

image-20200527152308267

输入主机名或主机IP

image-20200527152417077

然后远程主机名处点右键,可以看到监控远程java进程有两种方式:jmx连接和jstatd。

image-20200527152544522

其中,jmx监控配置相对来说比较简单,我使用的是jmx的方式来进行远程监控。具体配置方式如下:

启动配置

进入JDK目录:$JAVA_HOME/jre/lib/management

将jmxremote.password.template拷贝一份为:jmxremote.password

去掉注释:monitorRole QED controlRole R&D

添加监控参数

在需要监控的java进程中添加如下参数:

-Dcom.sun.management.jmxremote.port=9988 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false

然后重新启动java进程。

添加jmx连接

通过上面几项配置,则可以直接监控了。

image-20200527153338712

监控

由于我当前出现的问题是,向Flink提交任务,taskmanager会发送内存溢出情况。因此,为了尽快让它内存溢出,我调低了堆内存大小、堆外内存大小以及元数据空间大小。flink-conf.yaml配置如下:

env.java.opts.taskmanager: -Xms512m -Xmx512m -XX:MaxDirectMemorySize=256m -XX:MetaspaceSize=256m -Dcom.sun.management.jmxremote.port=9988 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

重新启动Flink后,频繁向flink提交任务(任务大约2s结束),查看内存情况。

检查配置参数是否生效

有时候配置错误或配置冲突时,配置或许并未见效,为了确定我刚刚配置的参数生效,我们可以查看一下配置。

ps -ef | grep [pid]
root      2126     1 46 15:39 pts/2    00:02:57 java -Xms512m -Xmx512m -XX:MaxDirectMemorySize=256m -XX:MaxMetaspaceSize=256m -Dcom.sun.management.jmxremote.port=9988 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -XX:NativeMemoryTracking=detail -XX:+PrintGCDetails -XX:NativeMemoryTracking=detail -XX:+PrintGCDetails -Dlog.file=
……………………

内存监控

image-20200602155341516

通过内存监视图可以看到,内存在持续不断的上涨。达到一定的值后(最大内存的80%),会触发GC。

但是,在linux中看到的java进程内存,是持续不断增大的。JVM管理的堆内存似乎没有泄漏问题。查看metaspace也是没有泄漏情况。

image-20200602155454781

堆内存正常,非堆内存是否也正常呢?通过jconsole监控,可以看出非堆内存如下:

image-20200602160724905

非堆内存也基本正常,但是TaskManager内存持续在增长。

一个java进程的内存可以简单总结为:jvm管理的内存和非jvm管理的内存。非jvm管理的内存是由系统直接管理。为了弄清是谁在持续不断的增加,在网上找了很多资料。

非堆内存监控

原生系统内存监控

在网上找到了这篇资料,和我本次遇到的问题有点类似,参考大佬们的踩坑记录来解决我当前的问题。

生成dot文件的过程此处先略过。下面是我们应用两次内存的对比:

图1:

图2:

通过对比,java.util.zip.Inflater 使用量会很高。

结论

在flink中,加载jar包会使用到上面的类,主要是在:FlinkUserCodeClassLoaders类中去加载和释放class。