JVM CPU 使用率高 问题两则

标签: JVM CPU 使用率高 | 发表时间:2014-10-25 20:14 | 作者:coderbee
出处:http://coderbee.net

最近有两个系统先后被恶意扫描,出现 CPU 使用率高的现象。很好,把问题暴露出来解决掉。

CPU 使用率很高,首先是要找出 CPU 在执行什么样的代码,然后在分析这些代码有什么问题。

一、问题定位

1、 用命令 “ps aux | grep APP” 找出应用的进程 id:

  801       84703  5.6 28.8 4627436 1132100 pts/2 Sl   11:08  11:19 /usr/jdk1.6.0_38/bin/java APP

2、 找出耗CPU的线程,在Linux系统下用命令: “ top –H –p pid ”, pid 就是前面找出来的应用进程 ID 。这个命令会显示出当前占用CPU高的线程。

  Tasks: 426 total,   0 running, 426 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.5%us,  0.6%sy,  0.0%ni, 72.3%id, 26.6%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3924912k total,  3308088k used,   616824k free,      768k buffers
Swap:  8388600k total,  3236720k used,  5151880k free,    12304k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
84784 appdeplo  20   0 4518m 1.1g 3816 S  0.4 29.0   0:00.85 java
84903 appdeplo  20   0 4518m 1.1g 3816 S  0.4 29.0   0:34.66 java
84983 appdeplo  20   0 4518m 1.1g 3816 S  0.4 29.0   0:00.99 java
85091 appdeplo  20   0 4518m 1.1g 3816 S  0.4 29.0   0:02.69 java
85164 appdeplo  20   0 4518m 1.1g 3816 S  0.4 29.0   0:04.92 java
84703 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:00.00 java
84704 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:00.42 java
84705 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:02.52 java
84706 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:02.64 java
84707 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:02.46 java
84708 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:02.39 java
84709 appdeplo  20   0 4518m 1.1g 3816 S  0.0 29.0   0:33.99 java

这里的 PID 比如 84784 是十进制的,需要转换为十六进制,用windows的计算器就可以转换了,转换为十六进制是: 14B30

3、 dump 出进程的所有线程栈,用命令 “./jstack -F -m -l 84703 > 84703.stack”84703 是 pid。
dump出的其中一个线程栈大概是这样的:

  "container-332" prio=10 tid=0x00007f4a044fa800 nid=0x13c7a runnable [0x00007f46e4ec8000]
   java.lang.Thread.State: RUNNABLE
         at java.net.SocketInputStream.socketRead0(Native Method)
         at java.net.SocketInputStream.read(SocketInputStream.java:129)
         at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
         at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
         - locked <0x0000000709252728> (a java.io.BufferedInputStream)
         at java.io.DataInputStream.readInt(DataInputStream.java:370)
         at com.ibm.mq.MQInternalCommunications.timedReadInt(MQInternalCommunications.java:2748)
         at com.ibm.mq.MQInternalCommunications.receiveBytesFaster(MQInternalCommunications.java:2846)
         - locked <0x00000007092524e0> (a com.ibm.mq.MQv6InternalCommunications)
         at com.ibm.mq.MQInternalCommunications.receive(MQInternalCommunications.java:1179)
         - locked <0x00000007092524e0> (a com.ibm.mq.MQv6InternalCommunications)
         at com.ibm.mq.MQSESSIONClient.lowLevelComms(MQSESSIONClient.java:2841)
         - locked <0x0000000709252e10> (a java.lang.Integer)
         at com.ibm.mq.MQSESSIONClient.MQGET(MQSESSIONClient.java:1852)
         at com.ibm.mq.MQQueue.getMsg2Int(MQQueue.java:1217)
         - locked <0x0000000760c4c738> (a com.ibm.mq.MQSPIQueue)
         at com.ibm.mq.MQQueue.getMsg2(MQQueue.java:1074)
         - locked <0x0000000760c4c738> (a com.ibm.mq.MQSPIQueue)
         at com.ibm.mq.jms.MQMessageConsumer.getMessage(MQMessageConsumer.java:3451)
         at com.ibm.mq.jms.MQMessageConsumer.receiveInternal(MQMessageConsumer.java:2866)
         at com.ibm.mq.jms.MQMessageConsumer.receive(MQMessageConsumer.java:2669)
         at com.ibm.mq.connector.outbound.MessageConsumerWrapper.receive(MessageConsumerWrapper.java:180)
         at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveMessage(AbstractPollingMessageListenerContainer.java:429)
         at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:310)
         at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263)
         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1058)
         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1050)
         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:947)
         at java.lang.Thread.run(Thread.java:662)

第一行的 nid 就是前面转换出来的十六进制数字,所有线程都有这样的对应线程栈。线程dump文件是文本文件,直接用文本编辑器查看就可以了。从上面的线程栈,我们就可以看到占用cpu高的线程在做什么。

二、问题分析

这两个问题虽然原因不同,但都可以通过上面的方法找到问题代码。

复杂正则导致 CPU 使用率高

从当时 dump 出来的线程栈来看,CPU 一直在执行正则匹配。

以前一直以为正则匹配是很高效的,其实不是。Java 的正则匹配采用的贪婪模式,也就是对每个模式,采用尽可能匹配最多个字符,当匹配不成功时,再回退,这样可能导致匹配的复杂度跟字符串的长度成阶乘的关系,可以看看这篇 文章的分析

随便写了个上百个字符的字符串去测试我们的正则,发现几个钟都没匹配完,汗!

HashMap 在并发访问下导致 CPU 使用率高

HashMap 是非线程安全的,在并发访问的情况下就可能出现死循环,这个死循环的分析网上很多了。Spring 的缓存模块(spring-modules-cache-0.7.jar)用它作为缓存,在平时并发访问度不高,没有问题,被恶意扫描时,就触发了死循环,可以看这个bug 报告 https://jira.spring.io/browse/MOD-371

相关 [jvm cpu 问题] 推荐:

JVM CPU 使用率高 问题两则

- - 码蜂笔记
最近有两个系统先后被恶意扫描,出现 CPU 使用率高的现象. CPU 使用率很高,首先是要找出 CPU 在执行什么样的代码,然后在分析这些代码有什么问题. 1、 用命令 “ps aux | grep APP” 找出应用的进程 id:. 2、 找出耗CPU的线程,在Linux系统下用命令: “ top –H –p pid ”, pid 就是前面找出来的应用进程 ID.

配置tomcat jvm 及cpu查看

- - Java - 编程语言 - ITeye博客
使用tomcat做为java容器,cpu占用偏高的原因,目前公司服务器上面跑的ubuntu环境nginx+tomcat+mysql运行一段时间之后java进程cpu偏高,会出现网站打不开的情况. 一,首先查看tomcat日志,如果有出现OOM错误(内存溢出)可以对应的加大jvm的内存大小. 1,修改tomcat目录下bin目录下的catalina.sh文件,在.

线上jvm进程CPU load高排查脚本-jkiller

- - 五四陈科学院-坚信科学,分享技术
以下内容由 [五四陈科学院]提供. 如果遇到线上java进程占用过多的cpu,可以用这个脚本来帮助你快速找到代码的问题. 先用top或者是jps定位占用cpu过多的java进程的pid是多少. 然后执行如下过程即可得到结论:. *centos系统下测试通过. 想快点找到作者也可以到Twitter上留言: @54chen.

JVM问题定位工具

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. JDB是基于文本和命令行的调试工具,Jikes在JDB的基础上提供了GUI. 熟悉JDB还是有价值的,很多情况下需要我们在命令行下完成简单的debug问题定位. 我们可能更熟悉使用下面这样的方式来进行调试,但本质上就是在使用JDB:.

JVM性能调优监控工具专题二:VisualVM基本篇之监控JVM内存,CPU,线程

- - ITeye博客
        上一个专题中讲述了JVM中自带的各种性能测试的小工具:包括jps,jstatck,jmap,jhat,jsats,hprof.         这样会造成不必要的麻烦,难道就没有一个tool可以 包括如上所有的功能. 答案是有的,自从 JDK 6 Update 7以后,提供了一全新的性能检测工具:VisualVM,VisualVM对运行中的Java应用提供了可视化的信息展示, 它是很多工具的整合包,整合了JConsole,jstat,jinfo,jstack以及jmap.

用MySQL Slow Log解决MySQL CPU占用高的问题

- - OurMySQL
   在Linux VPS系统上有时候会发现MySQL占用CPU高,导致系统的负载比较高. 这种情况很可能是某个SQL语句执行的时间太长导致的. 优化一下这个SQL语句或者优化一下这个SQL引用的某个表的索引一般能解决问题.    但是怎么找到是哪个SQL语句的执行时间过长呢. 可以通过MySQL Slow Log来找,详解如下.

java问题导致linux负载、cpu过高如何定位

- - CSDN博客推荐文章
1.用top找到最耗资源的进程id. 2.查询最消耗资源的java进程. 3.打印java 栈 信息. 4.将耗资源的javaPID转换为16进制(5920转1720<16进制>  去百度找 :十进制转十六进制). PID 对应 堆栈中的nid(16进制). 去stack.txt 中查找nid=1720的问题.

微软修复SVCHOST漏洞解决CPU利用率的问题

- - WPDang
SVCHOST是微软操作系统中的一项进程,微软官方对它的解释是:SVCHOST进程是从动态链接库(DLL)中运行的服务的通用主机进程名称. 这个程序对系统的正常运行是非常重要,而且是不能被结束的. 此前这个进程出现漏洞并困扰着许多用户长达几个月之久,这个漏洞使得XP系统运行过程中CPU的利用率居高不下.

java程序cpu占用过高问题分析

- - Web前端 - ITeye博客
针对某个java程序cpu占用过高问题分析,要想找到问题的真正原因,首先要明确cpu过高的进程,通过对进程下线程的分析,定位到具体的应用代码,从而定位问题的原因所在.     在jdk自带的分析工具中,通过jconsole只能分析到应用程序的相关系统资源使用情况,但无法定位应用程序,故通过此工具了解到应用程序存在问题,但要具体定位到哪块程序不合理造成的是很困难的.

java.util.zip.Deflater使用不当引发jvm crash及问题排查

- - Linux - 操作系统 - ITeye博客
最近使用第三方开源库jflvlib录制flv格式视频,测试过程发现,视频录制进程经常挂掉;. java启动参数中已经配置内存溢出时导出日志文件-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/export/Logs/xxx.dump和jvm crash的日志输出路径-XX:ErrorFile=/export/Logs/xxx.log,但是进程挂掉后没有找到任何日志输出;.