JVM自带性能分析工具介绍——jstack

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Roy_70/article/details/78021551

前言

JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,每一种工具都有其自身的特点,用户可以根据你需要检测的应用或者程序片段的状况,适当的选择相应的工具进行检测,这里我们就简要介绍下这几个命令的作用和使用方法。

命令 作用
jps 基础工具
jstack 查看某个Java进程内的线程堆栈信息
jmap jmap导出堆内存,然后使用jhat来进行分析
jhat jmap导出堆内存,然后使用jhat来进行分析
jstat JVM统计监测工具
hprof hprof能够展现CPU使用率,统计堆内存使用情况

jstack

jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:

jstack [option] pid  
jstack [option] executable core  
jstack [option] [server-id@]remote-hostname-or-ip

参数如下:

参数 作用
-l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)

使用例子:

[esv@bz3esvbs0ap1001 ~]$ jstack 46924
2017-09-18 15:23:52
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"Attach Listener" #12295 daemon prio=9 os_prio=0 tid=0x00007fc9d8019000 nid=0x2656 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"nioEventLoopGroup-87-1" #12290 prio=10 os_prio=0 tid=0x00007fc9bc21a800 nid=0x72e runnable [0x00007fc9dc5b8000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
        at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
        at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
        - locked <0x00000000ca3170a0> (a io.netty.channel.nio.SelectedSelectionKeySet)
        - locked <0x00000000ca3170c0> (a java.util.Collections$UnmodifiableSet)
        - locked <0x00000000ca317058> (a sun.nio.ch.EPollSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
        at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:622)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:310)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
        at java.lang.Thread.run(Thread.java:748)

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007fca0c07e800 nid=0xb752 in Object.wait() [0x00007fc9fcdfc000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x00000000c4276228> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
                    ..................
                    ..................
                    ..................
                    ..................
                    ..................
                    ..................
"main" #1 prio=5 os_prio=0 tid=0x00007fca0c008800 nid=0xb74d runnable [0x00007fca12939000]
   java.lang.Thread.State: RUNNABLE
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
        at java.net.ServerSocket.implAccept(ServerSocket.java:545)
        at java.net.ServerSocket.accept(ServerSocket.java:513)
        at org.apache.catalina.core.StandardServer.await(StandardServer.java:451)
        at org.apache.catalina.startup.Catalina.await(Catalina.java:777)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:723)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:321)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:455)

"VM Thread" os_prio=0 tid=0x00007fca0c072800 nid=0xb750 runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fca0c01e000 nid=0xb74e runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fca0c01f800 nid=0xb74f runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007fca0c0d6000 nid=0xb757 waiting on condition 

JNI global references: 245

另外, jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。
用例:
1.使用jps命令,获取需要调优的进程id为46924.
2.使用top -Hp 46924命令获得最耗费资源的线程号(pid), TIME列就是各个Java线程耗费的CPU时间,这里我们选58767线程作为例子.
这里写图片描述
3.使用printf “%x\n”,获得十六进制值。

[esv@bz3esvbs0ap1001 ~]$ printf "%x\n" 58767
e58f

4.使用jstack命令,它用来输出进程46924的堆栈信息,然后根据线程ID(58767)的十六进制值grep,如下:

[esv@bz3esvbs0ap1001 ~]$ jstack 46924 | grep e58f
"com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" #12278 daemon prio=5 os_prio=0 tid=0x00007fc9e40cf000 nid=0xe58f in Object.wait() [0x00007fc9b5353000]

这里就知道了最耗费时间的类是com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,Tomcat的线程池,方法是Object.wait()。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页