一次java内存top res高排查记录原创
前言
分享一个最近的问题,top 看java进程res不断升高,一天能涨3个G,使用jmap dump内存快照后,dump下来的文件只有300多M,没有发现内存泄漏。这是个什么情况呢,我们深入分析下。
冰山一角
首先,使用top来查看下当前进程的信息
可以看到top的res占用5.3g,jvm的参数如下
-Xmx8192M -Xms8192M -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDetails -XX:+PrintGCDateStamps -verbose:gc -Xloggc:/opt/ass/gc.log
早上的时候是4个g,下午的时候涨到7个g。
通过gc日志和gc次数和时间来看,fullgc并没有有效的清理掉内存。
我们使用jmap -histo:live pid
手动触发一次fullgc,发现res还在持续增长,也就是说内存肯定有泄漏的地方。
使用jmap dump出内存,查看泄漏的地方
jmap -dump:format=b,file=/opt/tmp/heapdump.hprof pid
dump下来发现,只有2个g,压缩后只有300M,分析内存中的数据,并没有泄漏的地方。
也就是说内存泄漏的地方可能在堆外。
分析堆外内存
NMT
NMT是Native Memory Tracking的缩写,是Java7U40引入的HotSpot新特性,开启后可以通过jcmd命令来对JVM内存使用情况进行跟踪。注意,根据Java官方文档,开启NMT会有5%-10%的性能损耗
-XX:NativeMemoryTracking=[off | summary | detail]
# off: 默认关闭
# summary: 只统计各个分类的内存使用情况.
# detail: Collect memory usage by individual call sites
添加-XX:NativeMemoryTracking=detail命令到启动参数中,然后重启项目。
执行
jcmd <pid> VM.native_memory summary scale=MB
由于我们使用的是jdk1.6,并不存在这个特性,所以只好用其他的办法。
ps
java -XX:+PrintFlagsFinal > flags.txt 可以看到当前java 支持所有xx的命令
pmap
pmap命令是Linux上用来开进程地址空间的
执行pmap -x | sort -n -k3 > pmap-sorted.txt命令可以根据实际内存排序
可以看到其他内存块占用的很少,最多的也只有60M,那也不可能是经典glibc的64M问题。
**pas+gdb
由于我们的不是内存地址段有问题,所以不dump出指定的范围的内存块。 如果是指定范围的内存块的话,可以这么操作
- • 查看当前进程的所有地址
cat /proc/pid/**aps > **pas.txt
查看**aps.txt,找到有问题的内存块地址,比如下图中的 7fa956967000-7fa956a65000
- • 启动gdb
gdb attach <pid>
- • dump指定范围的内存到指定的目录下,需要加0x
dump memory /tmp/0x7fa956967000-0x7fa956a65000.dump 0x7fa956967000 0x7fa956a65000
- • 显示长度超过10字符的字符串
strings -10 /tmp/0x7fa956967000-0x7fa956a65000.dump
- • dump 全部内存
由于我们这边内存都集中在一块,所以自己在业务低峰期,dump下了全部内存
- • 设置ulimit 查看ulimit
为了导出core文件,需要先设置ulimitulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 31722 max locked memory (kbytes, -l) 16384 max memory size (kbytes, -m) unlimited open files (-n) 65535 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 31722 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
ulimit -c unlimited
- • dump内容
gcore pid
- • 显示长度超过10字符的字符串
strings -10 core.pid > core.txt
查看内容后发现,内存中的数据是请求和响应的数据,查看代码后,怀疑是请求可能在某些情况下,没有正常的关闭。