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 -lpid>xxxfile
案例分析
现象:应用发布后,过二十分钟后load突然上升,居高不下. dump内存后没发现有内存泄漏,初步怀疑有线程在不断执行退不出.
验证:根据上面的方法找出占用cpu最高的java线程,dump出线程的后100行发现:
20881-thread-200" daemon prio=10 tid=0x0000000046edb800 nid=0x3bbb runnable [0x0000000044ad6000]
java.lang.Thread.State: RUNNABLE
at com.ibatis.sqlmap.engine.execution.SqlExecutor.getFirstResultSet(SqlExecutor.java:341)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.handleMultipleResults(SqlExecutor.java:299)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java:190)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(GeneralStatement.java:205)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForObject(GeneralStatement.java:104)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:566)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:541)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:106)
at org.springframework.orm.ibatis.SqlMapClientTemplate$1.doInSqlMapClient(SqlMapClientTemplate.java:273)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)
at org.springframework.orm.ibatis.SqlMapClientTemplate.queryForObject(SqlMapClientTemplate.java:271)
可以看到SqlExecutor.getFirstResultSet在这个地方一直处于runnable.打开源码如下:
[java] view plain copy
while (hasMoreResults) {
rs = stmt.getResultSet();
if (rs != null) {
break;
}
hasMoreResults = moveToNextResultsIfPresent(stmt);
}
debug后发现在这个地方一直死循环
原因:review dao代码时发现一条update的操作是用selectForObject来跑的,接手过来的历史代码伤不起啊,以前跑在oracle的时候不会出现这个问题,这次去o换成mysql后这个隐藏的雷终于爆发了.把相应的select改成update问题解决.
额外注意:问题能在测试环节发现,就不是问题,关键在于测试环节测试人员一直没发现这个问题,到线上一下子就出来了.原因有两个,一是测试环境走不到这个分支,也就是测试用例不充分;二是测试环境操作有限,死几个线程问题不大,因为测试环境设置的超时时间比较短,导致问题没有明显暴露出来,到线上一下子就出来了.
网友评论