排查Java服务CPU使用率高达100%的原因
Java服务在服务器运行一段时间,有一天CPU使用率突然高达100%,通过jstack工具分别在CPU使用率为100%时执行了一次堆线程dump和cpu使用率降下来后执行了一次堆线程dump
目录
- 排查Java服务CPU使用率高达100%的原因
- 一、环境信息
- 二、采集到的jstack堆内存信息
- 1、第一次Dump的堆内存信息
- 2、第二次Dump的堆内存信息
- 三、故障分析
- 1、故障原因分析
- 2、原理分析
一、环境信息
NO | 名称 | 信息 |
---|---|---|
1 | 操作系统 | Linux_64bit |
2 | CPU | - |
3 | 内存 | 32G |
4 | Java应用服务 | -Xmx3072m -Xmx3072m |
二、采集到的jstack堆内存信息
1、第一次Dump的堆内存信息
Heap
PSYoungGen total 801920K, used 278058K [0x00000007c0000000, 0x0000000800000000, 0x0000000800000000)
eden space 715008K, 26% used [0x00000007c0000000,0x00000007cbaaa868,0x00000007eba40000)
from space 86912K, 100% used [0x00000007fab20000,0x0000000800000000,0x0000000800000000)
to space 166784K, 0% used [0x00000007eba40000,0x00000007eba40000,0x00000007f5d20000)
ParOldGen total 2097152K, used 1904581K [0x0000000740000000, 0x00000007c0000000, 0x00000007c0000000)
object space 2097152K, 90% used [0x0000000740000000,0x00000007b43f1550,0x00000007c0000000)
PSPermGen total 85120K, used 84495K [0x0000000730000000, 0x0000000735320000, 0x0000000740000000)
object space 85120K, 99% used [0x0000000730000000,0x0000000735283f18,0x0000000735320000)
2、第二次Dump的堆内存信息
Heap
PSYoungGen total 876864K, used 468625K [0x00000007c0000000, 0x0000000800000000, 0x0000000800000000)
eden space 707456K, 53% used [0x00000007c0000000,0x00000007d725c7d8,0x00000007eb2e0000)
from space 169408K, 52% used [0x00000007f5a90000,0x00000007fb1d8000,0x0000000800000000)
to space 170560K, 0% used [0x00000007eb2e0000,0x00000007eb2e0000,0x00000007f5970000)
ParOldGen total 2097152K, used 1067610K [0x0000000740000000, 0x00000007c0000000, 0x00000007c0000000)
object space 2097152K, 50% used [0x0000000740000000,0x0000000781296a80,0x00000007c0000000)
PSPermGen total 85056K, used 84406K [0x0000000730000000, 0x0000000735310000, 0x0000000740000000)
object space 85056K, 99% used [0x0000000730000000,0x000000073526d998,0x0000000735310000)
三、故障分析
1、故障原因分析
-
通过两次Dump堆内存的比对,第一次Dump操作JVM堆内存中的老年代内存使用率高达90%(ParOldGen total 2097152K, used 1904581K [xxx] object space 2097152K, 90% used),第二次dump后显示JVM堆内存中的老年代内存使用率降到了50%(ParOldGen total 2097152K, used 1067610K [xxx] object space 2097152K, 50% used)。
-
导致此次故障的原因是老年代内存不断上涨,直到90%后触发了完全GC,使CPU使用率高达100%;当第二次Dump出堆线程信息显示,老年代的内存被完全GC回收了部分内存,使用率由回收前的90%降到了50%;
2、原理分析
下图为JVM内存结构模型(注意图中每个内存区域占用的比例y/x,y表示当前区域的分子,x表示堆内存分母)
根据内存模型,EIMServer的堆内存分配情况如下:
NO | 内存区 | 内存大小 |
---|---|---|
1 | 堆内存 | 3072MB |
2 | Yong区(新生代) | 1024MB |
3 | Eden区 | 819.2MB |
4 | Survivor区 | 204.8MB |
5 | Old区(老年代) | 2048MB |
JVM堆内存中创建一个对象是会先在Eden区申请并分配内存,如果新生代内存不足时会触发一次普通GC(内存回收),普通GC只释放Yong区的内存,通过扫描Eden区的对象,如果对象还有被引用,就将对象移入S0或S1区,如果Eden中的对象较大就会直接被移入老年代,然后将Eden区中所有不在被引用的对象全部释放;老年代内存区使用率达到90%时就会触发完全GC,完全GC时才会释放老年代内存区的内存,由于扫描的对象都是大对象,且引用数较大,所以会消耗大量的CPU资源,还会造成JVM短暂的无响应;