精华内容
下载资源
问答
  • 如何分析线程转储–线程堆栈跟踪
    2020-05-05 16:55:39
    本文是“ 线程转储”分析系列的第5部分。 到目前为止,您已经了解了线程的基本原理以及它们与Java EE容器和JVM的交互。 您还学习了HotSpot和IBM Java VM的不同线程转储格式。 现在是您深入分析过程的时候了。

    为了使您能够从线程转储中快速识别问题模式,首先需要了解如何读取线程堆栈跟踪以及如何正确获取“故事”。 这意味着,如果我要您告诉我#38线程在做什么? 您应该能够准确回答; 包括“线程堆栈跟踪”是否显示正常(正常)与挂起状态。

    再谈Java堆栈跟踪

    你们中的大多数人都熟悉Java堆栈跟踪。 当抛出Java异常时,这是我们从服务器和应用程序日志文件中找到的典型数据。 在这种情况下,Java堆栈跟踪为我们提供了触发Java异常的Thread的代码执行路径,例如java.lang.NoClassDefFoundError,java.lang.NullPpointerException等。此类代码执行路径使我们可以查看不同的层最终导致Java异常的代码。

    必须始终从下至上读取Java堆栈跟踪:

    • 底部的行将显示请求的始发者,例如Java / Java EE容器Thread。
    • 堆栈跟踪顶部的第一行将向您显示触发了最后一个Exception的Java类。

    让我们通过一个简单的示例来完成此过程。 我们创建了一个示例Java程序,只需执行一些Class方法调用并抛出Exception。 生成的程序输出如下:

    JavaStrackTraceSimulator
    Author: Pierre-Hugues Charbonneau
    http://javaeesupportpatterns.blogspot.com
    
    Exception in thread "main" java.lang.IllegalArgumentException:
            at org.ph.javaee.training.td.Class2.call(Class2.java:12)
            at org.ph.javaee.training.td.Class1.call(Class1.java:14)
            at org.ph.javaee.training.td.JavaSTSimulator.main(JavaSTSimulator.java:20)
    • 调用Java程序JavaSTSimulator(通过“主”线程)
    • 然后,模拟器从Class1调用方法call()
    • 然后,Class1方法call()调用Class2方法call()
    • Class2方法call()引发Java异常:java.lang.IllegalArgumentException
    • 然后,在日志/标准输出中显示Java异常

    如您所见,导致此异常的代码执行路径始终从下至上显示。

    上面的分析过程对于任何Java程序员都应该是众所周知的。 接下来,您将看到线程转储线程堆栈跟踪分析过程与上述Java堆栈跟踪分析非常相似。

    线程转储:线程堆栈跟踪分析

    从JVM生成的线程转储为您提供了整个JVM进程中所有“创建的”线程的代码级执行快照。 创建线程并不意味着所有这些线程实际上都在做某事。 在从Java EE容器JVM生成的典型线程转储快照中:

    • 一些线程可能正在执行原始计算任务,例如XML解析,IO /磁盘访问等。
    • 一些线程可能正在等待一些阻塞的IO调用,例如远程Web服务调用,DB / JDBC查询等。
    • 那时某些线程可能涉及垃圾回收,例如GC线程
    • 一些线程将等待一些工作要做(不做任何工作的线程通常进入wait()状态)
    • 一些线程可能正在等待其他一些线程完成工作,例如,一些线程正在等待获取某些对象上的监视器锁定(同步块{})

    在下一篇文章中,我将返回上面的更多图表,但现在让我们集中讨论堆栈跟踪分析过程。 您的下一个任务是能够尽您所能读取线程堆栈跟踪并了解它在做什么。

    线程堆栈跟踪为您提供了其当前执行的快照。 第一行通常包含线程的本机信息,例如其名称,状态,地址等。当前执行堆栈跟踪必须自下而上读取。 请遵循以下分析过程。 您从线程转储分析中获得的经验越多,您就能越快地读取并快速识别每个线程执行的工作:

    • 从底部开始读取线程堆栈跟踪
    • 首先,确定发起者(Java EE容器线程,自定义线程,GC线程,JVM内部线程,独立的Java程序“主”线程等)。
    • 下一步是确定线程正在执行的请求的类型(WebApp,Web Service,JMS,远程EJB(RMI),内部Java EE容器等)。
    • 下一步是从执行堆栈中识别出您所涉及的应用程序模块的形式,例如,线程正在尝试执行的实际核心工作。 分析的复杂性将取决于中间件环境和应用程序的抽象层
    • 下一步是查看第一行之前的最后〜10-20行。 标识线程所涉及的协议或工作,例如HTTP调用,套接字通信,JDBC或原始计算任务,例如磁盘访问,类加载等。
    • 下一步是看第一行。 第一行通常告诉LOT处于Thread状态,因为它是您拍摄快照时执行的当前代码
    • 最后两个步骤的组合将为您提供信息的核心,以总结线程所涉及的工作和/或悬挂条件

    现在,使用从JBoss 5生产环境捕获的Thread Dump Thread堆栈跟踪的真实示例,在下面直观地查看上述步骤。 在此示例中,许多线程在创建新的JAX-WS Service实例时都显示了类似的问题,即IO过多。
    thread_stack_trace_sample

    如您所见,最后10行和第一行将告诉我们线程所涉及的挂起或缓慢状态(如果有)。 底部的几行将为我们提供发起者和请求类型的详细信息。

    我希望本文能帮助您了解正确的线程堆栈跟踪分析的重要性。 当我们在以后的文章中介绍最常见的线程转储问题模式时,我将带回更多的线程堆栈跟踪示例。 现在,下一篇文章将教您如何在逻辑孤岛中分解线程转储线程,并提出潜在的根本原因“可疑”列表。

    参考: 如何分析线程转储–第5部分:来自JCG合作伙伴 Pierre-Hugues Charbonneau的Java EE支持模式和Java教程博客中的线程堆栈跟踪


    翻译自: https://www.javacodegeeks.com/2012/07/how-to-analyze-thread-dump-thread-stack.html

    更多相关内容
  • 获取Java线程转储的常用方法

    万次阅读 2021-01-07 21:26:48
    1. 线程转储简介 线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。 线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。 Java中的线程模型, 直接使用...

    1. 线程转储简介

    线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。

    线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。

    Java中的线程模型, 直接使用了操作系统的线程调度模型, 只进行简单的封装。

    线程调用栈, 也称为方法调用栈。 比如在程序执行过程中, 有一连串的方法调用链: obj1.method2 调用了 obj2.methodB, obj2.methodB 又调用了 obj3.methodC。 每个线程的状态都可以通过这种调用栈来表示。

    线程转储展示了各个线程的行为, 对于诊断和排查问题非常有用。

    下面我们通过具体示例, 来演示各种获取Java线程转储的工具, 以及使用方法。

    2. 使用JDK自带的工具

    我们一般使用JDK自带的命令行工具来获取Java应用程序的线程转储。 这些工具都在JDK主目录的bin文件夹下。

    所以, 只要配置好 PATH 路径即可。 如果不会配置, 可以参考: JDK环境准备

    2.1 jstack 工具

    jstack 是JDK内置的一款命令行工具, 专门用来查看线程状态, 也可以用来执行线程转储。

    一般先通过 jps 或者 ps 命令找到Java进程对应的pid, 然后在控制台中通过pid来输出线程转储。 当然, 我们也可以将输出内容重定向到某个文件中。

    使用jstack工具获取线程转储的基本参数格式为:

    jstack [-F] [-l] [-m] <pid>
    

    下面请看具体的演示:

    # 1. 查看帮助信息
    jstack -help
    

    输出的内容类似于:

    Usage:
        jstack [-l] <pid>
            (to connect to running process)
        jstack -F [-m] [-l] <pid>
            (to connect to a hung process)
        jstack [-m] [-l] <executable> <core>
            (to connect to a core file)
        jstack [-m] [-l] [server_id@]<remote server IP or hostname>
            (to connect to a remote debug server)
    
    Options:
        -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
        -m  to print both java and native frames (mixed mode)
        -l  long listing. Prints additional information about locks
        -h or -help to print this help message
    

    对应的参数选项是可选的。 具体含义如下:

    • -F 选项, 强制执行线程转储; 有时候 jstack pid 会假死, 则可以加上 -F 标志
    • -l 选项, 会查找堆内存中拥有的同步器以及资源锁
    • -m 选项, 额外打印 native栈帧(C和C++的)

    例如, 获取线程转储并将结果输出到文件:

    jstack -F 17264 > /tmp/threaddump.txt
    

    使用 jps 命令可以获取本地Java进程的 pid。

    2.2 Java Mission Control

    Java Mission Control(JMC)是一款客户端图形界面工具, 用于收集和分析Java应用程序的各种数据。
    启动JMC后, 首先会显示本地计算机上运行的Java进程列表。 当然也可以通过JMC连接到远程Java进程。

    可以鼠标右键单击对应的进程, 选择 “Start Flight Recording(开始飞行记录)” 。 结束之后, “Threads(线程)” 选项卡会显示“线程转储”:

    在这里插入图片描述

    2.3 jvisualvm

    jvisualvm 是一款客户端图形界面工具, 既简单又实用, 可用来监控 Java应用程序, 对JVM进行故障排查和性能分析。

    也可以用来获取线程转储。 鼠标右键单击Java进程, 选择“ Thread Dump”选项, 则可以创建线程转储, 完成后会在新选项卡中自动打开:

    在这里插入图片描述

    2.4 jcmd

    jcmd工具本质上是向目标JVM发送一串命令。 尽管支持很多功能, 但不支持连接远程JVM - 只能在Java进程的本地机器上使用。

    其中一个命令是 Thread.print, 用来获取线程转储, 示例用法如下:

    jcmd 17264 Thread.print
    

    2.5 jconsole

    jconsole 工具也可以查看线程栈跟踪。
    打开jconsole并连接到正在运行的Java进程, 导航到“线程”选项卡, 可以查看每个线程的堆栈跟踪:

    在这里插入图片描述

    2.6 小结

    事实证明, 可以使用JDK中的很多工具来获取线程转储。 让我们回顾一下, 并总结它们的优缺点:

    • jstack:获取线程转储最简单最方便的工具; Java 8之后可以使用 jcmd 工具来替代;
    • jmc:增强的JDK性能分析和问题诊断工具。 用这款工具进行性能分析的开销非常低。
    • jvisualvm:轻量级的开源分析工具, 图形界面非常棒, 还支持各种强悍的功能插件。
    • jcmd: 非常强大的本地工具, 支持Java 8及更高版本。 集成了多种工具的作用, 例如: 捕获线程转储(jstack), 堆转储(jmap), 查看系统属性和查看命令行参数(jinfo)
    • jconsole:也可以用来查看线程栈跟踪信息。

    3. 使用Linux命令

    在企业应用服务器中, 出于安全原因, 可能只安装了 JRE。 这时候没法使用这些JDK内置的工具。
    但还是有办法获取线程转储。

    3.1 使用 kill -3 指令

    在Unix/Linux之类的系统中, 可以使用 kill 命令获取线程转储, 底层实现原理, 则是通过系统调用 kill() 将信号参数发送给进程。 这里需要发送的是 -3 信号。

    一般先通过 jps 找到JAVA进程对应的pid, kill -3 使用示例如下:

    kill -3 17264
    

    3.2 Ctrl + Break (Windows)

    在Windows操作系统的命令行窗口中, 可使用组合键 Ctrl + Break 来获取线程转储。 当然, 需要先导航至启动Java程序的控制台窗口, 然后同时按下 CTRL键和Break键。

    需要注意的是, 某些键盘是没有 “Break” 键的。
    在这种情况下, 可以组合使用 CTRL, SHIFT, 以及 Pause键。

    这两个命令都可以将线程转储打印到控制台。

    4. 通过编程方式使用ThreadMxBean

    JMX技术支持各种各样的花式操作。 可通过 ThreadMxBean 来执行线程转储。

    示例代码如下:

    private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {
        StringBuffer threadDump = new StringBuffer(System.lineSeparator());
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {
            threadDump.append(threadInfo.toString());
        }
        return threadDump.toString();
    }
    

    上面代码做的事情很简单, 先通过 ManagementFactory 获取 ThreadMxBean 对象。
    方法的布尔参数 lockedMonitorslockedSynchronizers, 表示是否导出持有的同步器和管程锁。

    但是, 这种方法有一些缺陷:

      1. 性能不太好, 消耗的资源不少。
      1. threadDump.toString() 方法最多只会输出8个栈帧(MAX_FRAMES = 8); 可以拷贝 toString 代码并自己进行修改/过滤。
      1. 本地线程(比如GC线程)不会被Dump。

    替代方案:

      1. 通过 Runtime 调用 jstack 获取线程转储信息; 如果失败则回退到JMX方式;

    部分代码:

    
        public static String jStackThreadDump() {
            // 获取当前JVM进程的pid
            long currentPid = currentPid();
            // 组装命令
            String cmdarray[] = {
                    "jstack",
                    "" + currentPid
            };
            ProcessBuilder builder = new ProcessBuilder(cmdarray);
            String threadDump = "";
            try {
                Process p = builder.start();
                final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
                StringJoiner sj = new StringJoiner(System.lineSeparator());
                reader.lines().iterator().forEachRemaining(sj::add);
                threadDump = sj.toString();
                p.waitFor();
                p.destroy();
            } catch (Throwable e) {
                e.printStackTrace();
            }
            return threadDump;
        }
    
        public static long currentPid() {
            final long fallback = -1;
            final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
            final int index = jvmName.indexOf("@");
            if (index < 1) {
                return fallback;
            }
            String pid = jvmName.substring(0, index);
            if (null != pid && pid.matches("\\d+")) {
                return Long.parseLong(pid);
            }
            return fallback;
        }
    

    5. 总结

    我们通过具体示例展示了获取线程转储的各种方法。

    首先介绍的是各种JDK内置工具,
    然后讨论了命令行方式,
    最后介绍了JMX编程的方式。

    完整的示例代码请参考 GitHub仓库

    6. 附录: 线程状态及示例代码

    Thread 状态可参考 Thread.State, 包括:

    • NEW: 未启动; 比如还没执行(完) start 方法;
    • RUNNABLE : 可运行状态; 这是JVM的视角, 具体是否正在使用CPU则看操作系统调度;
    • BLOCKED : 阻塞状态; 比如进入同步方法/同步块, 等待锁资源;
    • WAITING : 等待锁资源, 比如 Unsafe.park(), Object.wait() 等。
    • TIMED_WAITING : 限时等待锁资源, 比如 Unsafe.park(), Object.wait() 等。
    • TERMINATED: 已终结; 线程的任务已执行完了。

    测试代码:

    
    import java.util.Objects;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    // 简单模拟线程的各种状态
    public class ThreadStateTest implements Runnable {
        public final Lock lock = new ReentrantLock(true);
        public final CountDownLatch beforeMonitorLatch = new CountDownLatch(1);
        public final CountDownLatch beforeLockLatch = new CountDownLatch(1);
        public final CountDownLatch toSleepLatch = new CountDownLatch(1);
    
        public static void main(String[] args) throws Exception {
            // Runnable task
            ThreadStateTest task = new ThreadStateTest();
            // 新创建线程对象
            Thread thread = new Thread(task);
            // 1. 线程未开始; NEW 状态;
            System.out.println("1. before start: thread.getState(): " + thread.getState());
            assertEquals(Thread.State.NEW, thread.getState());
            // 把重量锁抢了
            synchronized (task) {
                // 启动线程;
                thread.start();
                // 等待执行到要请求管程锁
                task.beforeMonitorLatch.await();
                TimeUnit.MILLISECONDS.sleep(100L);
                // 3. 线程在阻塞状态: 等待管程锁
                System.out.println("3. blocked by monitor: thread.getState(): " + thread.getState());
                assertEquals(Thread.State.BLOCKED, thread.getState());
                // 将轻量锁抢了
                task.lock.lock();
            }
            // 等待执行到要请求锁
            task.beforeLockLatch.await();
            // 稍微等一等
            TimeUnit.MILLISECONDS.sleep(100L);
            // 4. 等待状态; 此处是等待轻量锁;
            System.out.println("4. waiting lock: thread.getState(): " + thread.getState());
            assertEquals(Thread.State.WAITING, thread.getState());
            // 释放锁
            task.lock.unlock();
            // 让线程继续执行
            task.toSleepLatch.countDown();
            TimeUnit.MILLISECONDS.sleep(100);
            // 此时 thread 应该在睡眠中
            System.out.println("5.Thread in sleep: thread.getState(): " + thread.getState());
            assertEquals(Thread.State.TIMED_WAITING, thread.getState());
            // 等线程结束来汇合
            thread.join();
            System.out.println("6. after join: thread.getState(): " + thread.getState());
            assertEquals(Thread.State.TERMINATED, thread.getState());
        }
    
        @Override
        public void run() {
            System.out.println("=== enter run() ===");
            // 获取执行此任务的线程;
            Thread thread = Thread.currentThread();
            // 2. 线程在执行过程中; 在JVM看来属于可执行状态
            assertEquals(Thread.State.RUNNABLE, thread.getState());
            System.out.println("2. executing run: thread.getState(): " + thread.getState());
    
            //请求管程锁
            System.out.println("=== before synchronized (this)===");
            beforeMonitorLatch.countDown();
            synchronized (this) {
                System.out.println("===synchronized (this) enter===");
            }
    
            // 设置标识: 即将请求轻量锁
            beforeLockLatch.countDown();
            System.out.println("===before lock.lock()===");
            // 等待锁
            lock.lock();
            lock.unlock();
    
            try {
                // 等待标志: 需要睡眠
                this.toSleepLatch.await();
                // 睡眠500毫秒
                System.out.println("===before sleep()===");
                TimeUnit.MILLISECONDS.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("===finish run()===");
        }
    
        // 工具方法; 程序断言相等
        static public void assertEquals(Object expected, Object actual) {
            if (false == Objects.equals(expected, actual)) {
                throw new RuntimeException("Not Equals: expected=" + expected + "; actual=" + actual);
            }
        }
    }
    
    

    控制台输出的执行结果为:

    1. before start: thread.getState(): NEW
    === enter run() ===
    2. executing run: thread.getState(): RUNNABLE
    === before synchronized (this)===
    3. blocked by monitor: thread.getState(): BLOCKED
    ===synchronized (this) enter===
    ===before lock.lock()===
    4. waiting lock: thread.getState(): WAITING
    ===before sleep()===
    5.Thread in sleep: thread.getState(): TIMED_WAITING
    ===finish run()===
    6. after join: thread.getState(): TERMINATED
    

    相关链接:

    更多信息科参考:

    展开全文
  • 1. 线程转储简介线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。Java中的线程模型, 直接使用了...

    1. 线程转储简介

    线程转储(Thread Dump)就是JVM中所有线程状态信息的一次快照。

    线程转储一般使用文本格式, 可以将其保存到文本文件中, 然后人工查看和分析, 或者使用工具/API自动分析。

    Java中的线程模型, 直接使用了操作系统的线程调度模型, 只进行简单的封装。

    线程调用栈, 也称为方法调用栈。 比如在程序执行过程中, 有一连串的方法调用链:obj1.method2调用了obj2.methodB,obj2.methodB又调用了obj3.methodC。 每个线程的状态都可以通过这种调用栈来表示。

    线程转储展示了各个线程的行为, 对于诊断和排查问题非常有用。

    下面我们通过具体示例, 来演示各种获取Java线程转储的工具, 以及使用方法。

    2. 使用JDK自带的工具

    我们一般使用JDK自带的命令行工具来获取Java应用程序的线程转储。 这些工具都在JDK主目录的bin文件夹下。

    所以, 只要配置好 PATH 路径即可。 如果不会配置, 可以参考:JDK环境准备

    2.1 jstack 工具

    jstack 是JDK内置的一款命令行工具, 专门用来查看线程状态, 也可以用来执行线程转储。

    一般先通过jps或者ps命令找到Java进程对应的pid, 然后在控制台中通过pid来输出线程转储。 当然, 我们也可以将输出内容重定向到某个文件中。

    使用jstack工具获取线程转储的基本参数格式为:

    jstack [-F] [-l] [-m]

    下面请看具体的演示:

    # 1. 查看帮助信息

    jstack -help

    输出的内容类似于:

    Usage:

    jstack [-l]

    (to connect to running process)

    jstack -F [-m] [-l]

    (to connect to a hung process)

    jstack [-m] [-l]

    (to connect to a core file)

    jstack [-m] [-l] [server_id@]

    (to connect to a remote debug server)

    Options:

    -F to force a thread dump. Use when jstack does not respond (process is hung)

    -m to print both java and native frames (mixed mode)

    -l long listing. Prints additional information about locks

    -h or -help to print this help message

    对应的参数选项是可选的。 具体含义如下:

    -F选项, 强制执行线程转储; 有时候jstack pid会假死, 则可以加上-F标志

    -l选项, 会查找堆内存中拥有的同步器以及资源锁

    -m选项, 额外打印 native栈帧(C和C++的)

    例如, 获取线程转储并将结果输出到文件:

    jstack -F 17264 > /tmp/threaddump.txt

    使用jps命令可以获取本地Java进程的 pid。

    2.2 Java Mission Control

    Java Mission Control(JMC)是一款客户端图形界面工具, 用于收集和分析Java应用程序的各种数据。

    启动JMC后, 首先会显示本地计算机上运行的Java进程列表。 当然也可以通过JMC连接到远程Java进程。

    可以鼠标右键单击对应的进程, 选择 “Start Flight Recording(开始飞行记录)” 。 结束之后, “Threads(线程)” 选项卡会显示“线程转储”:

    2cb8078ab60dd216307ddb92534682cd.png

    2.3 jvisualvm

    jvisualvm 是一款客户端图形界面工具, 既简单又实用, 可用来监控 Java应用程序, 对JVM进行故障排查和性能分析。

    也可以用来获取线程转储。 鼠标右键单击Java进程, 选择“ Thread Dump”选项, 则可以创建线程转储, 完成后会在新选项卡中自动打开:

    b2a5e26852516a321da0f462379205d4.png

    2.4 jcmd

    jcmd工具本质上是向目标JVM发送一串命令。 尽管支持很多功能, 但不支持连接远程JVM - 只能在Java进程的本地机器上使用。

    其中一个命令是Thread.print, 用来获取线程转储, 示例用法如下:

    jcmd 17264 Thread.print

    2.5 jconsole

    jconsole 工具也可以查看线程栈跟踪。

    打开jconsole并连接到正在运行的Java进程, 导航到“线程”选项卡, 可以查看每个线程的堆栈跟踪:

    477c66914f02510407cba3a2bc826208.png

    2.6 小结

    事实证明, 可以使用JDK中的很多工具来获取线程转储。 让我们回顾一下, 并总结它们的优缺点:

    jstack

    jmc

    jvisualvm

    jcmd

    jconsole

    3. 使用Linux命令

    在企业应用服务器中, 出于安全原因, 可能只安装了 JRE。 这时候没法使用这些JDK内置的工具。

    但还是有办法获取线程转储。

    3.1 使用kill -3指令

    在Unix/Linux之类的系统中, 可以使用kill命令获取线程转储, 底层实现原理, 则是通过系统调用kill()将信号参数发送给进程。 这里需要发送的是-3信号。

    一般先通过jps找到JAVA进程对应的pid,kill -3使用示例如下:

    kill -3 17264

    3.2Ctrl + Break(Windows)

    在Windows操作系统的命令行窗口中, 可使用组合键Ctrl + Break来获取线程转储。 当然, 需要先导航至启动Java程序的控制台窗口, 然后同时按下CTRL键和Break键。

    需要注意的是, 某些键盘是没有 “Break” 键的。

    在这种情况下, 可以组合使用CTRL,SHIFT, 以及Pause键。

    这两个命令都可以将线程转储打印到控制台。

    4. 通过编程方式使用ThreadMxBean

    JMX技术支持各种各样的花式操作。 可通过ThreadMxBean来执行线程转储。

    示例代码如下:

    private static String threadDump(boolean lockedMonitors, boolean lockedSynchronizers) {

    StringBuffer threadDump = new StringBuffer(System.lineSeparator());

    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

    for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) {

    threadDump.append(threadInfo.toString());

    }

    return threadDump.toString();

    }

    上面代码做的事情很简单, 先通过ManagementFactory获取ThreadMxBean对象。

    方法的布尔参数lockedMonitors和lockedSynchronizers, 表示是否导出持有的同步器和管程锁。

    5. 总结

    我们通过具体示例展示了获取线程转储的各种方法。

    首先介绍的是各种JDK内置工具,

    然后讨论了命令行方式,

    最后介绍了JMX编程的方式。

    完整的示例代码请参考GitHub仓库。

    到此这篇关于获取Java线程转储的常用方法的文章就介绍到这了,更多相关Java线程转储内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    展开全文
  • jvm线程分析命令 ... 我的目标是与您分享我在过去10年中积累的有关线程转储分析的知识,例如数百个线程转储分析周期以及许多JVM版本和JVM供应商之间的数十种常见问题模式。 请将此页面添加为书签,并随...

    jvm线程分析命令

    本文将教您如何分析JVM线程转储,并查明问题的根本原因。 以我的观点,线程转储分析是掌握Java EE生产支持的任何个人最重要的技能。 您可以从线程转储快照中获取的信息量通常远远超出您的想象。

    我的目标是与您分享我在过去10年中积累的有关线程转储分析的知识,例如数百个线程转储分析周期以及许多JVM版本和JVM供应商之间的数十种常见问题模式。

    请将此页面添加为书签,并随时关注每周的文章。
    也请随时与您的工作同事和朋友分享此Thread Dump培训计划。

    听起来不错,我真的需要提高我的Thread Dump技能……那么我们从哪里开始呢?

    我向您提出的是一个完整的“线程转储”培训计划。 将涵盖以下项目。 我还将为您提供现实的线程转储示例,您可以学习和理解。

    1)线程转储概述和基础知识
    2)线程转储生成技术和可用工具
    3)Sun HotSpot,IBM JRE和Oracle JRockit之间的线程转储格式差异 4)线程堆栈跟踪的解释和解释 5)线程转储分析和相关技术 6)线程转储常见问题模式(线程争用,死锁,挂起IO调用,垃圾回收/ OutOfMemoryError问题,无限循环等) 7)通过实际案例研究得出的线程转储示例

    我真的希望此线程转储分析培训计划对您有所帮助,所以请继续关注每周更新和文章!

    但是,如果我仍然有疑问或仍在努力理解这些培训文章怎么办?

    不用担心,请考虑我为您的培训师。 我强烈建议您向我提问关于Thread Dump的任何问题记住,没有愚蠢的问题 ),因此我向您免费建议以下选项; 只需选择您更熟悉的通信模型即可:

    1)通过在文章下方发布您的评论来提交与主题转储相关的问题( 请随时保持匿名
    2)将线程转储数据提交到根本原因分析论坛
    3)给我发电子邮件与您的主题转储相关的问题@ phcharbonneau@hotmail.com

    我可以从生产环境/服务器向您发送线程转储数据吗?

    是的,如果您想讨论问题的根本原因,请随时通过电子邮件或“ 根本原因分析”论坛将您生成的线程转储数据发送给我。 现实生活中的线程转储分析始终是最好的学习方法。

    我真的希望您会喜欢并分享此线程转储分析培训计划。 我会尽力为您提供优质的材料和任何问题的答案。

    在深入研究线程转储分析和问题模式之前,了解基础知识非常重要。 这篇文章将介绍基础知识,并让您更好地与Java EE容器进行JVM和中间件交互。

    Java VM概述

    Java虚拟机实际上是任何Java EE平台的基础。 这是您的中间件和应用程序已部署并处于活动状态的地方。

    JVM为中间件软件和Java / Java EE程序提供以下功能:

    – Java / Java EE程序的运行时环境(字节码格式)
    –几个程序功能和实用程序(IO设施,数据结构,线程管理,安全性,监视等)
    –通过垃圾回收器动态分配和管理内存

    您的JVM可以驻留在许多操作系统(Solaris,AIX,Windows等)上,并且根据您的物理服务器规格,您可以为每个物理/虚拟服务器安装1…n个JVM进程。

    JVM和中间件软件交互

    在下面找到一个图,该图向您显示JVM,中间件和应用程序之间的高级交互视图。

    这向您展示了JVM,中间件和应用程序之间的典型且简单的交互图。 如您所见,标准Java EE应用程序的线程分配主要在中间件内核本身和JVM之间完成( 当应用程序本身或某些API直接创建线程时会有一些例外,但这并不常见,必须非常小心地进行 ) 。

    另外,请注意,某些线程在JVM本身内部进行管理,例如GC(垃圾收集)线程,以便处理并发垃圾收集。

    由于大多数线程分配是由Java EE容器完成的,因此了解并识别线程堆栈跟踪并从线程转储数据中正确识别它很重要,这一点很重要。 这将使您快速了解Java EE容器尝试执行的请求的类型。

    从线程转储分析的角度来看,您将学习如何区分从JVM找到的不同线程池并确定请求类型。

    最后一部分将为您概述什么是HotSpot VM的JVM线程转储以及您将发现的不同线程。 第4部分将提供IBM VM线程转储格式的详细信息。

    请注意,您可以从根本原因分析论坛中找到本文使用的线程转储示例。

    JVM线程转储–这是什么?

    JVM线程转储是在给定时间拍摄的快照,可为您提供所有已创建的Java线程的完整列表。

    找到的每个单独的Java线程都会为您提供以下信息:

    线程名称 ; 通常由中间件供应商用于标识线程ID及其关联的线程池名称和状态(运行,阻塞等)。

    线程类型和优先级,例如: 守护程序prio = 3 **中间件软件通常将其线程创建为守护程序,这意味着它们的线程在后台运行; 向用户提供服务,例如您的Java EE应用程序**

    Java线程ID,例如: tid = 0x000000011e52a800 **这是通过java.lang.Thread.getId()获得的Java线程ID,通常实现为长1..n **的自动递增

    –本机线程ID,例如: nid = 0x251c **作为本机线程ID的重要信息,您可以关联例如从OS角度来看哪个线程在JVM中使用最多的CPU等。

    Java线程状态和详细信息,例如: 等待监视器条目[0xfffffffea5afb000] java.lang.Thread.State:已阻止(在对象监视器上)
    **允许快速了解线程状态及其潜在的电流阻塞条件**

    Java线程堆栈跟踪 ; 这是迄今为止您可以从线程转储中找到的最重要的数据。 这也是您将花费大部分时间的地方,因为Java Stack Trace为您提供了90%的信息,以便查明许多问题模式类型的根本原因,您将在稍后的培训课程中学习

    Java堆故障 ; 从HotSpot VM 1.6开始,您还将在“线程转储”快照的底部找到HotSpot内存空间利用率的细分,例如Java堆(YoungGen,OldGen)和PermGen空间。 当怀疑过多的GC是可能的根本原因时,这非常有用,因此您可以对发现的线程数据/模式进行开箱即用的关联

    Heap
    PSYoungGen      total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000)
    eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)
    from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)
    to   space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)
    PSOldGen        total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000)
    object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)
    PSPermGen       total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000)
    object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)

    线程转储故障概览

    为了让您更好地理解,请在下面的图表中直观地查看HotSpot VM线程转储及其常见的线程池:

    您可以从HotSpot VM线程转储中找到一些信息。 根据您的问题模式,其中一些功能比其他功能更重要(问题模式将在以后的文章中进行模拟和解释)。

    现在,根据我们的示例 HotSpot线程转储,在下面找到每个线程转储部分的详细说明:

    #全线程转储标识符
    基本上,这是唯一的关键字,一旦生成线程转储(例如,对于UNIX,通过kill -3 <PID>),您就会在中间件/标准Java输出日志中找到该关键字。 这是“线程转储”快照数据的开始。

    Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.0-b11 mixed mode):

    #Java EE中间件,第三方和自定义应用程序线程
    这部分是线程转储的核心,通常您将在其中花费大部分分析时间。 找到的线程数将取决于您使用的中间件软件,第三方库(可能具有自己的线程)和您的应用程序( 如果创建任何自定义线程,通常不是最佳实践 )。

    在我们的示例线程转储中,Weblogic是所使用的中间件。 从Weblogic 9.2开始,使用具有唯一标识符“'weblogic.kernel.Default(自我调整)”的自我调整线程池。

    "[STANDBY] ExecuteThread: '414' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=3 tid=0x000000010916a800 nid=0x2613 in Object.wait() [0xfffffffe9edff000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0xffffffff27d44de0> (a weblogic.work.ExecuteThread)
            at java.lang.Object.wait(Object.java:485)
            at weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:160)
            - locked <0xffffffff27d44de0> (a weblogic.work.ExecuteThread)
            at weblogic.work.ExecuteThread.run(ExecuteThread.java:181)

    #HotSpot VM线程
    这是由HotSpot VM管理的内部线程,以执行内部本机操作。 通常,除非看到较高的CPU(通过线程转储和prstat /本机线程ID相关性),否则您不必担心这一点。

    "VM Periodic Task Thread" prio=3 tid=0x0000000101238800 nid=0x19 waiting on condition

    #HotSpot GC线程
    当使用HotSpot并行GC时(在使用多物理核心硬件的情况下这很普遍),默认情况下或根据JVM调整一定数量的GC线程,HotSpot VM会创建。 这些GC线程允许VM以并行方式执行其定期GC清理,从而总体上减少了GC时间。 以增加CPU利用率为代价。

    "GC task thread#0 (ParallelGC)" prio=3 tid=0x0000000100120000 nid=0x3 runnable
    "GC task thread#1 (ParallelGC)" prio=3 tid=0x0000000100131000 nid=0x4 runnable
    ………………………………………………………………………………………………………………………………………………………………

    这也是至关重要的数据,因为当面临与GC相关的问题(例如过多的GC,内存泄漏等)时,您将能够使用其本机id值(nid)将在OS / Java进程中观察到的任何高CPU与这些线程相关联= 0x3)。 您将在以后的文章中学习如何识别和确认此问题。

    #JNI全局引用计数
    JNI(Java本机接口)全局引用基本上是从本机代码到Java垃圾收集器管理的Java对象的对象引用。 其作用是防止收集本机代码仍在使用但技术上在Java代码中没有“实时”引用的对象。

    监视JNI引用以检测与JNI相关的泄漏也很重要。 如果您直接使用JNI进行编程,或者使用易于发生本机内存泄漏的第三方工具(例如监视工具)进行编程,则可能会发生这种情况。

    JNI global references: 1925

    #Java堆利用率视图
    此数据已添加回JDK 1 .6,并为您提供了HotSpot Heap的简短快速视图。 我发现在与GC相关的问题以及HIGH CPU一起进行故障排除时,它非常有用,因为您可以在单个快照中同时获得线程转储和Java堆,从而可以确定(或排除)特定Java堆内存空间中的任何压力点以及当前当时正在执行线程计算。 正如您在示例线程转储中所看到的,Java Heap OldGen已被最大化!

    Heap
     PSYoungGen      total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000)
      eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000)
      from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000)
      to   space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000)
     PSOldGen        total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000)
      object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000)
     PSPermGen       total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000)
      object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)

    我希望本文有助于理解HotSpot VM线程转储的基本视图。下一篇文章将为您提供IBM VM的相同线程转储概述和故障排除。

    请随时发表任何评论或问题。

    参考: 如何分析线程转储–第1部分  如何分析线程转储–第2部分:JVM概述 如何分析线程转储–第3部分: 来自JCG合作伙伴的 HotSpot VM   Java EE支持模式和Java教程”博客上的Pierre-Hugues Charbonneau。


    翻译自: https://www.javacodegeeks.com/2012/03/jvm-how-to-analyze-thread-dump.html

    jvm线程分析命令

    展开全文
  • 监视JVM线程并在给定时间内阻塞线程时保存线程转储。 用法 从下载jar 将其添加到要监视的应用程序的命令行中: java -javaagent:jvm-monitoring-agent-0.9.0.jar=threshold=1000,debug ...rest of command 配置...
  • java-Websph中的javacore,线程转储和堆转储之间的区别有人可以告诉我javacore,线程转储和堆转储之间的确切区别吗? 在哪种情况下使用这些?5个解决方案53 votes线程转储是所有活动线程的堆栈的转储。 因此对于分析...
  • 本文将教您如何分析JVM线程转储,并查明问题的根本原因。 从我的角度来看,线程转储分析是掌握Java EE生产支持的任何个人最重要的技能。 您可以从线程转储快照中获取的信息量通常远远超出您的想象。 我的目标是与您...
  • 线程转储分析

    2016-09-17 22:39:00
     在具体分析线程转储数据之前,我们首先要明确线程的状态。java.lang.Thread.State枚举类中定义了如下几种类型: NEW:线程创建尚未启动。 RUNNABLE:包括操作系统线程状态中的Ready和Running,可能在等待时间...
  • Java线程转储分析器 这是用Java编写的Java线程转储分析器。 它基于的。 有关用法的其他信息,请参见 。 执照 Java Thread Dump Analyzer是根据。 版权所有2014-2016 Spotify AB 版权所有2016-2018 MP Objects BV...
  • 该工具允许用户加载,可视化和分析Visual VM生成的Java线程转储。 请参阅Wiki,以获取快速入门指南和教程。
  • 以下说明是针对Weblogic Application Server进行线程转储的,这有助于在其他情况下对WebLogic进行故障排除。 Windows ctrl+break UNIX/Linux 通过ps -ef | grep java获取WebLogic Java进程的PID 在UNIX会话...
  • 锁定可视化 用于可视化 Java 线程转储的项目。
  • Java线程转储分析

    2017-06-27 16:32:11
     在具体分析线程转储数据之前,我们首先要明确线程的状态。java.lang.Thread.State枚举类中定义了如下几种类型: NEW:线程创建尚未启动。RUNNABLE:包括操作系统线程状态中的Ready和Running,可能在等待时间片...
  • 它是jstack线程转储中的NID。 在Windows上,它只是进程中的操作系统级线程ID。 在Linux和Solaris上,它是线程的PID(这又是一个轻量级的过程)。 在Mac OS X上,它被称为本机pthread_t值。转到此链接:Java级别的线程...
  • Java并发之线程转储

    2019-10-08 02:37:36
    一、java线程转储 java的线程转储可以被定义为JVM中在某一个给定的时刻运行的所有线程的快照。一个线程转储可能包含一个单独的线程或者多个线程。在多线程环境中,比如J2EE应用服务器,将会有许多线程和线程组。每...
  • 实现功能内容:手动配置weblogic控制台用户名和密码,自动监控weblogic独占或者粘滞,自动转储问题线程,自动上传转储线程日志,自动实现发送短信,自动实现中文语音播报。
  • jstackfx, JStackFX,用于分析线程转储的工具 命令行上下文分析线程转储作为由 jstack 工具生成的文件提供原始的文本文件并不容易。 这就是我为什么要开发 JStackFX 。要求JStackFX需要你的系统上最新的JDK 8.插件...
  • 在Linux上运行时,如何在JBoss中生成线程转储? 如何在Linux上生成JBoss堆栈跟踪? 如何将kill -3的输出重定向到文件? JBoss的cpu使用率很高,冻结,挂起或不释放空闲线程,如何获取线程转储进行故障排除? JMS...
  • 线程转储是诊断CPU尖峰,死锁,内存问题,无响应的应用程序,较差的响应时间以及其他系统问题的重要工件。 有很多很棒的在线线程转储分析工具,可以分析和发现问题。但是对于那些工具,您需要提供适当的线程转储作为...
  • 因此,我最近发现对线程转储感兴趣。以下是使用VisualVM(适用于Java的内置工具)从Web应用程序摘录的几行内容:"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]java.lang.Thread....
  • 本文是我们的线程转储分析系列的第4部分,它将为您概述什么是IBM VM的JVM线程转储以及您将找到的不同线程和数据点。 您将看到和学习​​到,IBM VM Thread Dump格式是不同的,但是提供了更多现成的故障排除数据。 在...
  • IDEA生成线程转储信息

    2018-10-30 11:18:31
  • I want to know what a java thread dump is.Can someone please help me understand what a thread dump is and how it relates to a running java program?解决方案A Java thread dump is a way of finding out ...
  • 转储被上传到 Amazon S3。 此应用程序还捆绑了用于通过 ssh 命令行访问部署容器。 支持使用 Tomcat 作为部署容器的 java-buildpack 应用程序。 此应用程序旨在添加到 java-buildpack 分支,以便诊断应用程序...
  • 关于Java线程转储分析

    千次阅读 2016-12-18 13:52:48
    关于Java线程转储分析 达人科技 2016-09-19 15:31 一、线程状态 在具体分析线程转储数据之前,我们首先要明确线程的状态。java.lang.Thread.State枚举类中定义了如下几种类型: NEW:线程创建尚未...
  • Java 线程转储

    2017-03-04 09:39:50
    为了可以理解/分析线程转储,首先要理解线程转储的各个部分。让我们先拿一个简单的线程堆栈为例,并且去了解他的每个部分。 "ExecuteThread: '1' " daemon prio=5 tid=0x628330 nid=0xf runnable [0xe4881000..0...
  • 在分析性能问题时,我每5秒进行一次连续线程转储,然后使用武士线程转储分析器进行分析.注意,许多线程处于可运行状态,并且在所有情况下,堆栈堆栈下面的内容连续不断.但是我找不到他们正在与哪个主机通信.我尝试使用...
  • jmc线程转储 本文是我们的线程转储分析系列的第4部分,它将为您提供什么是IBM VM的JVM线程转储以及您将找到的不同线程和数据点的概述。 您将看到和学习​​到,IBM VM Thread Dump格式是不同的,但是提供了更多现成...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,665
精华内容 12,266
关键字:

线程转储