前面文章我们已经提到过了JDK自带的jstack是使用的Dynamic Attach机制。下面是官方文档对该机制的描述,
This is a Sun private mechanism that allows an external process to start a thread in HotSpot that can then be used to launch an agent to run in that HotSpot, and to send information about the state of HotSpot back to the external process.
那么现在的问题也就变成了external process跟target VM process间的IPC问题了,那么到底是使用了什么样的IPC方式呢,
On Linux and Solaris, the client creates a file named .attach_pid
<pid>
and sends a SIGQUIT to the target JVM process. The existence of this file causes the SIGQUIT handler in HotSpot to start the attach listener thread. On Windows, the client uses the Win32 CreateRemoteThread function to create a new thread in the target process. The attach listener thread then communicates with the source JVM in an OS dependent manner:
- On Solaris, the Doors IPC mechanism is used. The door is attached to a file in the file system so that clients can access it.
- On Linux, a Unix domain socket is used. This socket is bound to a file in the filesystem so that clients can access it.
- On Windows, the created thread is given the name of a pipe which is served by the client. The result of the operations are written to this pipe by the target JVM.
也就是说,以Linux平台为栗,使用了两种IPC方式,
- 信号机制。首先external process会先发送一个SIGQUIT信号给target VM process,target VM会创建一个Attach Listener线程;
- Unix domain socket。然后Attach Listener线程会通过Unix domain socket与external process建立连接,之后就可以基于这个socket进行通信了。
这个过程中,会有两个文件被创建,
- .attach_pid
<pid>
,external process会创建这个文件,为的是触发Attach Listener线程的创建,因为SIGQUIT信号不是只有external process才会发的,通过这个文件来告诉target VM,有attach请求过来了。相关代码在LinuxVirtualMachine.java中; - .java_pid
<pid>
,target VM会创建这个文件,这个是因为Unix domain socket本身的实现机制需要去创建一个文件,通过这个文件来进行IPC。相关代码在attachListener_linux.cpp中;
其中的<pid>
都是target VM的pid。