注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭州 QA Team

务实 专注 分享 做有态度的QA

 
 
 
 
 

日志

 
 

轻巧的线程堆栈查看工具Hot Threads  

来自张伟杰   2014-03-25 20:40:54|  分类: 性能测试 |举报 |字号 订阅

  下载LOFTER 我的照片书  |
定位性能问题,尤其是cpu使用率过高时,经常需要查找cpu消耗较高的线程,然后查看其堆栈,从而进入代码定位问题。

该场景下, jstack+top是一种非常经典的方式。

jstack+top
jstack+top的一般套路:
1、top -H 查看cpu占用较高的线程,记录十进制的线程id
2、jstack  将线程信息dump到文件中,在文件中根据线程id查找该线程的堆栈。 注意,jstack输出中线程id是16进制的,这里要做一次进制转换。 
3、研究这个线程的堆栈

jstack+top方法的不足:
1、麻烦。由于top工具输出是实时变化的,一般需要抓多次,重复下来,上述过程更显繁琐。
2、线程状态时刻变动,top -H时看到一个线程的cpu占用率较高,等到jstack 时可能已经处于sleep状态,因此上述操作需要较高的APM



有什么办法能省却这些麻烦 —— 能在看到线程堆栈的时候,直接看到他们各自的cpu占用率呢? —— Hot Threads 可以!

 Hot Threads

Hot Threads是一个小巧的开源工具,使用十分容易:
1、下载jar包,扔到服务器上
2、执行java -jar HotThread.jar [pid] 即可,pid是被测的进程号。使用中注意填对路径即可。

Hot Threads的输出:
执行完上述指令后,Hot Threads会在很短时间内,重复查询10次线程堆栈信息(调用sun.management.ThreadImpl.getThreadInfo方法),统计平均cpu占用最高的3个线程,打印线程堆栈,并显示cpu占用率。
106.3% CPU Usage by Thread 'Swing-Shell'
  10/10 snapshots sharing following 10 elements
    sun.awt.shell.Win32ShellFolder2.getAttributes0(Native Method)
    sun.awt.shell.Win32ShellFolder2.access$600(Unknown Source)
    sun.awt.shell.Win32ShellFolder2$6.call(Unknown Source)
    sun.awt.shell.Win32ShellFolder2$6.call(Unknown Source)
    java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    java.util.concurrent.FutureTask.run(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    sun.awt.shell.Win32ShellFolderManager2$ComInvoker$3.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

1.6% CPU Usage by Thread 'RMI TCP Connection(9)-172.30.41.210'
  10/10 snapshots sharing following 32 elements
    sun.management.ThreadImpl.getThreadInfo0(Native Method)
    sun.management.ThreadImpl.getThreadInfo(Unknown Source)
    sun.reflect.GeneratedMethodAccessor106.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.ConvertingMethod.invokeWithOpenReturn(Unknown Source)
    com.sun.jmx.mbeanserver.MXBeanIntrospector.invokeM2(Unknown Source)
    com.sun.jmx.mbeanserver.MXBeanIntrospector.invokeM2(Unknown Source)
    com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(Unknown Source)
    com.sun.jmx.mbeanserver.PerInterface.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.MBeanSupport.invoke(Unknown Source)
    javax.management.StandardMBean.invoke(Unknown Source)
    com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(Unknown Source)
    com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.doOperation(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.access$200(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(Unknown Source)
    javax.management.remote.rmi.RMIConnectionImpl.invoke(Unknown Source)
    sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    java.lang.reflect.Method.invoke(Unknown Source)
    sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
    sun.rmi.transport.Transport$1.run(Unknown Source)
    java.security.AccessController.doPrivileged(Native Method)
    sun.rmi.transport.Transport.serviceCall(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

0.0% CPU Usage by Thread 'Reference Handler'
  10/10 snapshots sharing following 3 elements
    java.lang.Object.wait(Native Method)
    java.lang.Object.wait(Object.java:485)
    java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
上图中,每个线程的能看到 10/10 标记。 n / m 意味着m次统计中,有n次都是该排名。  


Hot Threads使用中的问题和解决方法:
直接执行java -jar HotThread.jar [pid]可能会报错,此时可以换一种启动方式:
java -classpath "/opt/jdk1.6/lib/tools.jar:HotThread.jar" hotthread.Main [pid]

其中 /opt/jdk1.6/lib/tools.jar 是服务器上jdk tools包的完整路径,hotthread.Main Hot Threads程序的入口。


Hot Threads的不足:
使用中发现,Hot Threads自身的cpu开销比较高,有时候统计显示cpu使用率第一的线程,在执行的是获取线程信息的操作,该条堆栈对分析问题无效。
2723.0% CPU Usage by Thread 'RMI TCP Connection(4)-192.168.164.87' 
  6/10 snapshots sharing following 33 elements 
    sun.management.ThreadImpl.getThreadInfo1(Native Method) 
    sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:154) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 


总结: 
Hot Threads使用快速轻巧, 在需要使用jstack + top的场合,都可以尝试代替比较繁琐的jstack + top。 






  评论这张
 
阅读(1222)| 评论(6)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016