前言
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()。