正文
背景
周四时某项目在QQ群里说自己的系统出现了CPU占用较高的情况.
TOP 查看发现大部分占用CPU的都是 JAVA核心进城后附近的进程.
所以初步怀疑 是出现了FullGC的问题.
然后群里反馈了dump 以及 tracelog等内容
进行了简单的分析, 这里总结一下, 备忘
关于GC进程
java -jar 进行启动服务时
第一个进程是核心进程.
第二个一般是 DestroyVM的进程.
然后CPU核心个数的进程一般是GC进程.
查看办法一般为: Top 然后输入 大写 P 按照CPU使用率进行排序.
比如本次给出来的 jstack的处理
进程号是: 89622
然后可以获取 16进制的 编码为: printf +%x 89622
结果为: 15e16
文件搜索 15e17
进程信息为:
"DestroyJavaVM" #487 prio=5 os_prio=0 tid=0x00007f4e2b411000 nid=0x15e17
其他的GC进程为:
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f4f4001f800 nid=0x15e18
因为有 12个CPU 所以就会有12个GC进程.
然后就会再有一个VM的进程
"VM Thread" os_prio=0 tid=0x00007f4f40272000 nid=0x15e25 runnable
然后会有 : Reference Handler 和 Finalizer 以及 Signal Dispatcher 三个JVM的进程
然后后面就是 C1和C2的编译进程了
关于GC进程
大部分可以通过简单的10进制和16进制转换就可以简单看出来 哪些进程有问题.
GC进程多说明堆区存在问题, 有内存泄露或者是大对象, 或者是配置较低.
如果是编译进程较多, 可能是CodeCache存在异常配置.
不同占用CPU的情况是不一样的 可以进行一些简单的分析和定位.
关于dump分析
使用mat分析即可,这个非常简单.
然后打开 dominator tree的方式可以 查看哪些内存占用较多.
也可以直接打开 memory leak detect的来进行判断
本次发现一个比较诡异的数据
org.springframework.data.redis.connection.util.ByteArrayWrapper
这个名称的对象有 四千万个.
占用内存大约 4G左右
感觉打个对象占用100bytes的字节进行计算
4千万*100bytes = 40M*0.1KB = 4GB
与结果完全一致, 基本上发现了内存泄漏的点
然后告诉不重启服务 第二天再次抓取dump
发现内存对象从3.75千万到了4.05千万
工作时间大约也就4个小时不到战胜了 300万行记录
计算一周时间. (40/4)*0.3千万=3千万记录
基本上符合数据的情况. 也明确了内存泄漏的点.
一个另外的思路
抓取dump进行分析需要mat工具并且抓取和下载,以及分析都比较耗时.
感觉这一块 是可以优化的.
然后使用抓取内存对象数目的方式进行验证:
jcmd $pid GC.class_histogram -all >zhaobsh.txt
然后搜索 org.springframework.data.redis.connection.util.ByteArrayWrapper 查看变量数据.
num #instances #bytes class name
3: 33433500 802404000 org.springframework.data.redis.connection.util.ByteArrayWrapper
逐个进行分析
第一个数字 代表他的对象数目排第三位.
第二个数字 代表元素的总数量. 这里面是三千三百万.
第三个数字 是占用的内存大小. (不一定是最终大小.)
这个命令只需要三秒钟就可以查询出结果. 比dump要简单非常多.
感觉可以在操作命令前后进行两次跟踪就可以判断补丁的修改是否凑效了.