JStack实现浅析

相信Java程序员对jstack都不陌生,今天我们坑进OpenJDK源码来看看jstack是怎么实现的。
通过官方文档的介绍,我们可以知道jstack的源码在OpenJDK的jdk子项目下,sun.tools.jstack.JStack

/*
 * This class is the main class for the JStack utility. It parses its arguments
 * and decides if the command should be executed by the SA JStack tool or by
 * obtained the thread dump from a target process using the VM attach mechanism
 */
public class JStack { ... }

通过注释我们可以知道,jstack会根据不同参数决定使用不同的方式来进行thread dump:使用SA的JStack,或者使用attach机制。
通过代码可以看到,下面三种情况会使用SA的JStack,

  • 使用了-m选项;
  • 使用了-F选项;
  • 不是对本地进程而是对远程server执行jstack;

下面我们来看下使用attach机制实现的thread dump(SA的实现就先欠着啦:)。
关于attach机制,暴露给用户的其实就是Attach API,其底层实现,简单来讲就是在虚拟机启动了一个Attach Listener,外部进程通过UNIX socket与其进行通信,发送一些命令让Attach Listener去执行。具体可以参考官方文档或者这一篇博文
下面我们来看下jstack是如何使用attach机制的。runThreadDump方法,

    // Attach to pid and perform a thread dump
    private static void runThreadDump(String pid, String args[]) throws Exception {
        VirtualMachine vm = null;
        try {
            ///////////////////////////////////
            // 使用 Attach API
            ///////////////////////////////////
            vm = VirtualMachine.attach(pid);
        } catch (Exception x) {
            String msg = x.getMessage();
            if (msg != null) {
                System.err.println(pid + ": " + msg);
            } else {
                x.printStackTrace();
            }
            if ((x instanceof AttachNotSupportedException) &&
                (loadSAClass() != null)) {
                System.err.println("The -F option can be used when the target " +
                    "process is not responding");
            }
            System.exit(1);
        }

        ///////////////////////////////////
        // 发送命令执行thread dump
        ///////////////////////////////////
        // Cast to HotSpotVirtualMachine as this is implementation specific
        // method.
        InputStream in = ((HotSpotVirtualMachine)vm).remoteDataDump((Object[])args);

        // read to EOF and just print output
        byte b[] = new byte[256];
        int n;
        do {
            n = in.read(b);
            if (n > 0) {
                String s = new String(b, 0, n, "UTF-8");
                System.out.print(s);
            }
        } while (n > 0);
        in.close();
        vm.detach();
    }

可以看到最后是通过HotSpotVirtualMachine#remoteDataDump来执行thread dump。来看下这个方法

    // Remote ctrl-break. The output of the ctrl-break actions can
    // be read from the input stream.
    public InputStream remoteDataDump(Object ... args) throws IOException {
        return executeCommand("threaddump", args);
    }
    private InputStream executeCommand(String cmd, Object ... args) throws IOException {
        try {
            return execute(cmd, args);
        } catch (AgentLoadException x) {
            throw new InternalError("Should not get here", x);
        }
    }

继续往下跟代码到Linux平台上的实现,LinuxVirtualMachine#execute,可以看到最终通过UNIX socket与Attach Listener进行了通信,发送的就是上面看到的threaddump命令。Attach Listener对接收到的命令所执行的操作,在attachListener.cpp

// names must be of length <= AttachOperation::name_length_max
static AttachOperationFunctionInfo funcs[] = {
  { "agentProperties",  get_agent_properties },
  { "datadump",         data_dump },
  { "dumpheap",         dump_heap },
  { "load",             JvmtiExport::load_agent_library },
  { "properties",       get_system_properties },
  { "threaddump",       thread_dump },
  { "inspectheap",      heap_inspection },
  { "setflag",          set_flag },
  { "printflag",        print_flag },
  { "jcmd",             jcmd },
  { NULL,               NULL }
};

看下threaddump所对应的thread_dump方法,

// Implementation of "threaddump" command - essentially a remote ctrl-break
// See also: ThreadDumpDCmd class
//
static jint thread_dump(AttachOperation* op, outputStream* out) {
  bool print_concurrent_locks = false;
  if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
    print_concurrent_locks = true;
  }

  // thread stacks
  VM_PrintThreads op1(out, print_concurrent_locks);
  VMThread::execute(&op1);

  // JNI global handles
  VM_PrintJNI op2(out);
  VMThread::execute(&op2);

  // Deadlock detection
  VM_FindDeadlocks op3(out);
  VMThread::execute(&op3);

  return JNI_OK;
}

所以再往下就得坑进HotSpot的源码,VMThread::execute,才能看到最终HotSpot是怎么执行的thread dump了。这里就不继续挖坑了,感兴趣的同学可以继续跟下去 ^_^

嗯,今天就先到这,have fun la

03-18
<think>好的,用户想了解jstack工具的使用方法和相关教程。首先,我需要回忆一下jstack的基本功能和常见用途。jstack是Java虚拟机自带的命令行工具,用于生成线程转储,帮助诊断线程问题,比如死锁、死循环、高CPU占用等。接下来,我需要整理用户提供的引用内容,确保信息准确。 根据引用[1],jstack的基本用法包括连接到运行中的进程、挂起的进程、核心文件或远程调试服务器。需要详细说明各个参数的作用,比如-F、-m、-l的区别。引用[2]提到jstack用于获取线程堆栈跟踪,分析性能问题和死锁。引用[3]和[4]解释了线程快照的作用,以及在程序崩溃时使用jstack分析core文件的情况。 用户可能需要知道如何获取线程转储,分析结果,以及实际应用场景。例如,如何检测死锁?这时候需要示例说明。此外,常见问题如权限不足、进程未响应等,应该给出解决方法。 还要注意用户可能遇到的困难,比如如何定位高CPU占用的线程。需要结合操作系统的命令,如top或ps,找到线程ID,再转换为十六进制,在jstack输出中查找对应的堆栈信息。 最后,生成相关问题要考虑用户可能的后续疑问,比如如何自动化线程转储、与其他工具配合使用,或者如何处理转储文件的分析。确保问题覆盖使用场景、高级参数、结果分析等各个方面。 现在整理结构,分步骤说明使用方法,附上示例,并确保符合格式要求,比如数学公式用$...$,独立公式用$$...$$,但这里可能用不到太多数学公式,重点在代码和命令示例。检查LaTeX语法正确,使用中文回答,结构清晰,分步骤讲解。引用标注放在相关段落末尾,自然添加。 需要验证各个参数是否正确,比如-F参数在强制转储时的应用场景,-m显示本地方法栈的信息。同时,权限问题可能导致jstack无法连接,需要提示用户以正确权限运行。进程挂起时使用-F参数,可能需要结合其他命令如kill -3。 确保回答覆盖基础命令、参数解析、示例分析、常见问题解决,以及相关应用场景。这样用户能全面了解jstack的使用方法和实际应用。</think>### jstack 使用详解 jstack 是 Java 虚拟机(JVM)提供的命令行工具,用于生成 Java 应用程序的线程快照(thread dump)。通过分析线程状态,可定位性能问题、死锁、资源争用等问题[^2][^4]。以下是具体使用方法: --- #### 一、基础命令格式 ```bash jstack [options] <pid> # 连接到运行中的 Java 进程 jstack -F [options] <pid> # 强制生成堆栈信息(适用于挂起进程) jstack [options] <executable> <core> # 分析核心转储文件 jstack [options] [server_id@]<remote_host> # 连接到远程调试服务器 ``` --- #### 二、参数解析 | 参数 | 说明 | |------|------| | `-l` | 显示锁的附加信息(如持有锁的线程) | | `-m` | 输出本地方法(Native Method)的堆栈信息 | | `-F` | 强制生成堆栈信息(适用于进程未响应场景) | --- #### 三、操作示例 1. **获取 Java 进程 ID** ```bash jps -l # 输出示例:1234 com.example.Main ``` 2. **生成线程快照** ```bash jstack -l 1234 > thread_dump.txt ``` 3.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值