环境:centos
运行程序: springMVC的web服务
容器:jetty
一、背景
我们有一个应用,在上线之后,监控到内存可用率随着运行时间逐步下降,从上线之初的50%,运行一段时间后下降到20%左右。机器上有其他进程也占内存,我想确定下是否是内存泄漏导致的,查清楚后也能对线上的应用运行情况有更好掌握,如果有内存泄漏查出原因进行解决,避免隐患的发生。
二、 排查过程
整体的排查步骤如下:
- Java的堆内存和metaspace等内存排查。使用的工具是:Jconsole、JVisualVM、arthas、strace。
- Java堆外内存分析排查。使用的命令:jcmd
- 进程的原生内存排查。使用的工具:google的gperftools、gdb、pmap、smaps、jcmd、jstack。
其中还有一些linux的命令:free、top等。
2.1 Java的堆内存和metaspace等内存排查
jetty服务器开启jmx监控(不会的可以查一下怎么开启监控)后,利用jdk自带的jconsole和jvisualvm工具开始对应用进行监控。
jconsole能够监控的项有:
- 内存:能够堆的各项指标变化,包括新生代、老年代、伊甸园区和survivor区的变化,同时也能看到非堆区的变化,包括metaspace、code_cache、direct、compressed_class_space和mapped等。
- 线程:能够看到各个线程的情况。还能够检测到是否有死锁。
- 类:能够看到加载类和卸载类的各种情况。
- VM概要:能够看到启动进程的环境变量,以及jvm大的reserved和conmmited的大小等。
- MBean:能够看到内存的各个对象指标。
jvisualvm能够监控的项有:
- CPU 使用情况和垃圾回收情况
- 堆和metaspace:能够看到堆的整体使用情况,以及metaspace的变化。
- 类:能够看到加载类和卸载类的各种情况。
- 线程:能够看到各种线程的状态和使用情况,活动线程和守护线程等。
- 监控采样:cpu和内存堆。这个功能很强大,能够观测随着应用的运行,产生了哪些对象,特别是增量对比功能,对于内存泄漏的排查有很大的用处,一般持续增多的对象,一直不释放就有可呢鞥是内存泄漏的源头。
阿里的arthas工具具有的监控项有:
- dashboard:能够实时显示当前进程的heap和noheap的使用情况。
- trace 能够追踪到具体的方法是谁调用的。
- 火焰图:能够看到进程的内存热点图。
通过以上工具,观察到进程的GC频率、堆的使用一直处于良好的状态,堆内的GC能够及时的回收无用的对象。可以排除堆内存泄漏的原因。
通过以上工具也能排除metaspace、code_cache、direct、compressed_class_space和mapped
2.2 Java堆外内存分析排查
接着开始排查java进程中是不是有第三方库使用了DirectByteBuffer操作堆外内存导致的泄露。因为需要监控JVM堆外内存,所以需在重启的JVM启动参数中加入
-XX:NativeMemoryTracking=detail
同时编写了一个定时采集进程的JVM内存的小工具(bash脚本:capture.sh),主要内容如下:
for (( i=1; i <= 100000;i++))
do