您的位置:

jstack-l解析

一、什么是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应用程序中的问题非常有帮助。