java 一个pid导致cpu过高分析

java进程 cpu load过高分析过程
1\  jps -v列出所有的java进程 , top找出cpu占用过高的对应的java 进程pid

2\ 使用top -H -p PID 命令查看对应进程里的哪个线程占用CPU过高,取该线程pid

3\ 将线程的pid 转成16进制

4\jstack [进程pid]|grep -A 100 [线程pid的16进制]  dump出jvm该线程的后100行,或者整个输出到文件

jstack -l pid > xxxfile

案例分析 
现象:应用发布后,过二十分钟后load突然上升,居高不下. dump内存后没发现有内存泄漏,初步怀疑有线程在不断执行退不出.
验证:根据上面的方法找出占用cpu最高的java线程,dump出线程的后100行发现:
[java] view plain copy
  1. 20881-thread-200" daemon prio=10 tid=0x0000000046edb800 nid=0x3bbb runnable [0x0000000044ad6000]  
  2.    java.lang.Thread.State: RUNNABLE  
  3.    at com.ibatis.sqlmap.engine.execution.SqlExecutor.getFirstResultSet(SqlExecutor.java:341)  
  4.    at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleMultipleResults(SqlExecutor.java:299)  
  5.    at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:190)  
  6.    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:205)  
  7.    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)  
  8.    at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:104)  
  9.    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:566)  
  10.    at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:541)  
  11.    at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:106)  
  12.    at org.springframework.orm.ibatis.SqlMapClientTemplate$1.doInSqlMapClient(SqlMapClientTemplate.java:273)  
  13.    at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)  
  14.    at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:271)  

可以看到SqlExecutor.getFirstResultSet在这个地方一直处于runnable.打开源码如下:

[java]  view plain copy
  1. while (hasMoreResults) {  
  2.      rs = stmt.getResultSet();  
  3.      if (rs != null) {  
  4.        break;  
  5.      }  
  6.      hasMoreResults = moveToNextResultsIfPresent(stmt);  
  7.    }  

debug后发现在这个地方一直死循环

原因:review dao代码时发现一条update的操作是用selectForObject来跑的,接手过来的历史代码伤不起啊,以前跑在oracle的时候不会出现这个问题,这次去o换成mysql后这个隐藏的雷终于爆发了.把相应的select改成update问题解决.

额外注意:问题能在测试环节发现,就不是问题,关键在于测试环节测试人员一直没发现这个问题,到线上一下子就出来了.原因有两个,一是测试环境走不到这个分支,也就是测试用例不充分;二是测试环境操作有限,死几个线程问题不大,因为测试环境设置的超时时间比较短,导致问题没有明显暴露出来,到线上一下子就出来了.

你可能感兴趣的:(调优)