关于Attach API:
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.
这是Sun私有实现(即不是Jvm标准规范,其他虚拟机不一定有这个能力)。该api的功能是让外部进程可以 在目标JVM(运行被监控、被控制的程序的JVM) 中启动一个线程,该线程会加载运行Agent,然后线程会将本jvm的状态返回给外部进程。
public abstract class VirtualMachine
extends Object
该类表示将要被“附着的”Java虚拟机,也被称为目标虚拟机(target virtual machine,target vm)。 外部进程(通常来说是外部的监控工具、或是管理控制台,如jconsole,jprofile) 使用该类实例来 将agent 加载到目标虚拟机中。 例如,使用Java编写的profiler工具就会使用VirtaulMachine类实例来加载profiler agent到被监控的jvm中。
通过VirtualMachine的类静态方法attach(string id)来获取代表target vm的VirtaulMachine实例。该方法 id参数一般是arget vm的进程Pid。
另外,也可以 通过 类静态方法 attach(VirtualMachineDescriptor vmd) 来获取一个VirtaulMachine实例( 可以使用静态方法VirtualMachine.list()方法获取一个VirtualMachineDescriptor 列表 )。
当获取到VirtualMachine对象实例后,就可以调用loadAgent,loadAgentLibrary,loadAgentPath方法操作target VM了。
这几个方法的区别:
描述符 | 方法签名 | 描述 |
---|---|---|
protected | VirtualMachine(AttachProvider provider, String id) | (构造函数,私有) Initializes a new instance of this class. |
static | VirtualMachine attach(String id) | Attaches to a Java virtual machine. |
static | VirtualMachine attach(VirtualMachineDescriptor vmd) | Attaches to a Java virtual machine. |
abstract | void detach() | Detach from the virtual machine. |
abstract | Properties getAgentProperties() | Returns the current agent properties in the target virtual machine. |
abstract | Properties getSystemProperties() | Returns the current system properties in the target virtual machine. |
String | id() | Returns the identifier for this Java virtual machine. |
static | List list() | Return a list of Java virtual machines. |
void loadAgent(String agent) | Loads an agent. | |
abstract | void loadAgent(String agent, String options) | Loads an agent. |
void loadAgentLibrary(String agentLibrary) | Loads an agent library. | |
abstract | void loadAgentLibrary(String agentLibrary, String options) | Loads an agent library. |
void | loadAgentPath(String agentPath) | |
abstract | void loadAgentPath(String agentPath, String options) | Load a native agent library by full pathname. |
AttachProvider provider() | Returns the provider that created this virtual machine. | |
String toString() | Returns the string representation of the VirtualMachine. | |
int | hashCode() | Returns a hash-code value for this VirtualMachine. |
boolean | equals(Object ob) | Tests this VirtualMachine for equality with another object. |
// attach to target VM
VirtualMachine vm = VirtualMachine.attach("2177");
// get system properties in target VM
Properties props = vm.getSystemProperties();
// construct path to management agent
String home = props.getProperty("java.home");
String agent = home + File.separator + "lib" + File.separator
+ "management-agent.jar";
// load agent into target VM
vm.loadAgent(agent, "com.sun.management.jmxremote.port=5000");
// detach
vm.detach();
public final class AttachPermission
extends BasicPermission
当设置了 SecurityManager后,在外部程序调用VirtalMachine.attach时,target VM会检查外部程序的权限。
当创建AttachProvider时,会也检查你的权限。
AttachPermission对象包含一个名字(目前不知道操作列表这种细化的权限)。
对象构造:
attachVirtualMachine 与createAttachProvider 的区别:
参考:http://ifeve.com/jvm-attach/
在Linux下,attach时,外部进程会在目标进程的cwd目录下创建文件:/proc//cwd/.attach_pid。 然后等待给JVM下的所有线程发送SIGQUIT信号,再作轮询等待看目标进程是否创建了某个文件,attachTimeout默认超时时间是5000ms,可通过设置系统变量sun.tools.attach.attachTimeout来指定。
JVM在启动时,会创建“Signal Dispatcher”线程。当外部进程给所有子进程发送SIGQUIT信号,而JVM将信号就传给了“Signal Dispatcher”(其他线程对该信号进行了屏蔽)。
对于Signal Dispatcher线程: 当信号是SIGBREAK(在jvm里做了#define,其实就是SIGQUIT)的时候,就会触发AttachListener::is_init_trigger()的执行,创建出AttachListener线程。
AttachListener线程:AttachListener线程创建了一个监听套接字,并创建了一个文件/tmp/.java_pid,这个文件就是外部进程之前一直在轮询等待的文件,随着这个文件的生成,意味着attach的过程圆满结束了。
attach listener接收请求
该线程不断从队列中取AttachOperation,然后找到请求命令对应的方法进行执行。比如jstack的 thread dump命令命令,attach listener找到 { “threaddump”, thread_dump }的映射关系,然后执行thread_dump方法