一、什么是jstack-l
jstack-l是一种Java HotSpot VM的命令行工具,用于生成Java堆栈信息的文本文件。这对于分析Java应用程序的内存问题非常有用,因为它可以向我们展示Java堆中正在运行的线程的状态,并告诉我们线程正在执行的代码行。
可以使用此工具检测线程死锁,并可发现一些问题,如线程阻塞、内存泄漏等。同时,对于高并发应用程序,它也非常有用,因为它可以帮助我们查找并解决性能问题。
二、jstack-l的使用方法
可以使用以下命令来生成jstack-l的输出:
jstack -l <PID> > <filename.txt>
这将生成一个名为“filename.txt”的文本文件,其中包含Java Heap中正在运行的线程信息。在大多数情况下,您需要手动运行此命令,并将输出发送到支持人员以进行分析。
例如,在Linux机器上,我们可以运行以下命令来生成jstack-l的输出文件:
jstack -l 1000 > /tmp/jstack.txt
这将生成一个名为“jstack.txt”的文本文件,在/tmp目录下。
三、如何分析jstack-l的输出
1. 查看线程状态
jstack-l的输出会为我们提供Java Heap中正在运行的线程信息。从输出中,我们可以查看每个线程的状态,如RUNNABLE、WAITING、TIMED_WAITING等。
"http-nio-8080-AsyncTimeout" #30 daemon prio=5 os_prio=0 tid=0x00007f038c004000 nid=0x5a1 waiting on condition [0x00007f037cff8000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at org.apache.catalina.core.AsyncTimeout$AsyncTimeoutTimer.run(AsyncTimeout.java:295)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
该线程的状态为“TIMED_WAITING”,即它正在等待一段时间后再次运行。这是由线程调度器控制的等待类型。
2. 查看线程栈信息
jstack-l的输出还将为我们提供有关线程堆栈的详细信息。从输出中,我们可以查看每个线程正在执行的代码行。
"http-nio-8080-AsyncTimeout" #30 daemon prio=5 os_prio=0 tid=0x00007f038c004000 nid=0x5a1 waiting on condition [0x00007f037cff8000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at org.apache.catalina.core.AsyncTimeout$AsyncTimeoutTimer.run(AsyncTimeout.java:295)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
该线程正在执行的代码行是“java.lang.Thread.sleep(Native Method)”和“org.apache.catalina.core.AsyncTimeout$AsyncTimeoutTimer.run(AsyncTimeout.java:295)”。
3. 查看线程锁
jstack-l的输出还将为我们提供有关每个线程正在锁定的对象的详细信息。从输出中,我们可以查看每个对象以及该对象正在被哪个线程锁定。
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.app.MyRunnable.run(MyRunnable.java:16)
- locked <0x000000076ad20fd8> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
该线程正在等待一个锁对象,该锁对象被另一个线程锁定,并且该信息还告诉了我们锁定该对象的线程:
- locked <0x000000076ad20fd8> (a java.lang.Object)
4. 查看CPU使用情况
jstack-l的输出还将为我们提供有关Java虚拟机正在使用的CPU情况的详细信息。从输出中,我们可以查看当前Java线程正在使用的CPU时间,以便我们了解哪些线程使用了最多的CPU。
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 <0x0000000711975b10> (a io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x0000000580aabed8> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000007119371b0> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:748)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:408)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
at java.lang.Thread.run(Thread.java:745)
此信息告诉我们该线程正在运行,并且正在使用CPU时间。
四、结论
jstack-l是一个非常有用的工具,它可以帮助我们分析Java应用程序的内存问题和线程问题。通过使用jstack-l,我们可以查看Java堆中正在运行的线程状态、线程栈信息、线程锁状态和CPU使用情况。这对于解决Java应用程序中的问题非常有帮助。