部分机器CPU使用率99% 问题分析

背景:

收到cpu使用率报警,应用中多台机器cpu使用率高达99%左右。

部分机器CPU使用率99% 问题分析_第1张图片

 

初步处理:

第一时间重启一台机器,发现使用率恢复正常。陆续重启其它机器,保留一台用于观察分析问题根源。

分析:

  1. 初步观察这台机器的内存监控,网络监控等都基本正常。并且观察近几天的cpu使用率情况,基本都正常,就上截图中时间,突然升高。
  2. 通过堡垒机,连到该机器,top命令,发现确实java进程cpu使用率高达90%多。
  3. top -H -p #pid,进一步观察进程中线程,cpu使用率情况;发现有多个线程,cpu使用率稳定在20%左右。
  4. 通过jstack命令,获取jvm线程堆栈快照文件。
  5. 把线程ID,10进制转16进制,在快照文件中搜索,发现该线程是GC线程。也就是说,cpu使用率高,是由于full gc引起的。
  6. 第一步的时候,只观察了机器的内存监控,忽略了jvm。观察jvm 监控,发现堆内存几乎使用完,在频繁的full gc,但是堆内存释放很少。
  7. Jmap Dump下来jvm快照文件,通过mat分析发现,有一对象占比很大。是Xstream解析xml消息相关的。
  8. 分析应用近期上线,有一个mq消费是xml格式的消息,是用的Xstream解析的,但是每次消息解析,都是新new的Xstream,并且为Xstream设置了一个很长的字符串数组属性。

分析总结:

分析由于该消息量非常大,当在中午10点左右的时候,达到峰值,频繁的new大对象,导致新生代young gc回收不过来,直接放入老年代,full gc回收内存释放不够的情况下,频繁的full gc,最终导致cpu使用率达到90%以上。

解决方案:

Xstream修改为单例模式,上线后观察,cpu,jvm等持续保持稳定。

 

附:Full GC 触发条件:

Full GC的触发条件大致情况有以下几种情况:

1. 程序执行了System.gc() //建议jvm执行fullgc,并不一定会执行;

2. 执行了jmap -histo:live pid命令 //这个会立即触发fullgc;

3. 在执行minor gc的时候进行的一系列检查:

a. 执行Minor GC的时候,JVM会检查老年代中最大连续可用空间是否大于了当前新生代所有对象的总大小。

b. 如果大于,则直接执行Minor GC(这个时候执行是没有风险的)。

c. 如果小于了,JVM会检查是否开启了空间分配担保机制,如果没有开启则直接改为执行Full GC。

d. 如果开启了,则JVM会检查老年代中最大连续可用空间是否大于了历次晋升到老年代中的平均大小,如果小于则执行改为执行Full GC。

e. 如果大于则会执行Minor GC,如果Minor GC执行失败则会执行Full GC

4.  使用了大对象 //大对象会直接进入老年代

5.  在程序中长期持有了对象的引用,对象年龄达到指定阈值也会进入老年代

 

 

 

 

 

 

欢迎关注公众号:“架构一线”,定期分享一些实战心得,互联网前沿技术等.

你可能感兴趣的:(JVM)