浅谈jvm中Instrumentation的实现

想必不少人听说过javaagent,但是很少人听说Instrumentation,其实Instrumentation就是javaagent的实现机制,说到Instrumentation,就必须想了解javaattach机制,那就先说下attach的实现。
浅谈jvm中Instrumentation的实现_第1张图片
        大家进行jstack的时候,是不是经常看到两个线程Signal Dispatcher Attach Listener线程,可能不知道是干嘛的吧,这两个线程是实现attach的关键所在,其中前者是在jvm启动的时候就会创建的,后者只有接收过attach请求的时候vm才会创建,顾名思义,Signal Dispatcher是分发信号的, Attach Listener 是处理attach请求的,那么两者有什么关系呢,当我们执行attach方法的时候,会向目标vm发出一个SIGQUIT 的信号,目标vm收到这个信号之后就会创建Attach Listener线程了,当然jvm保证了不会多创建。

 1  path = findSocketFile(pid);
 2          if (path ==  null) {
 3             File f =  new File(tmpdir, ".attach_pid" + pid);
 4             createAttachFile(f.getPath());
 5              try {
 6                 sendQuitTo(pid);
 7 
 8                  //  give the target VM time to start the attach mechanism
 9                  int i = 0;
10                  long delay = 200;
11                  int retries = ( int)(attachTimeout() / delay);
12                  do {
13                      try {
14                         Thread.sleep(delay);
15                     }  catch (InterruptedException x) { }
16                     path = findSocketFile(pid);
17                     i++;
18                 }  while (i <= retries && path ==  null);
19                  if (path ==  null) {
20                      throw  new AttachNotSupportedException(
21                         "Unable to open socket file: target process not responding " +
22                         "or HotSpot VM not loaded");
23                 }
24             }  finally {
25                 f.delete();
26             }
27         }

        Attach机制说得简单点就是提供A进程可以连上B进程(当然是java进程),创建socket进行通信,A通过发命令给B,B然后对命令进行截取从自己的vm中获取信息发回给客户端vm,但是并不是随便发指令都会处理的,那么attach Listener接收哪些命令呢,如下所示

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 }
};

         Instrumentation的实现其实主要使用了load这个指令,它用来实现让target vm动态加载agentlib,Instrumentation的实现在一个名为libinstrument.dylib的动态lib库,linux下是libinstrument.so,它是基于jvmti接口实现的,因此在对其进行load的时候会创建一个agent实例,并往jvmti环境注册一些回调方法,比如监听类文件加载的事件,vm初始化完成事件等,执行Agent_OnAttach,这里会创建一个Instrumentation实例并返回给用户供大家扩展Instrumentation,比如增加一些transform。并会执行Instrumentation实例的loadClassAndCallAgentmain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的agentmain方法,当vm初始化完毕之后,会调用loadClassAndCallPremain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的pre main方法。在类进行加载的时候会调用Instrumentation的transform方法,可以看看参数里有个byte数组,这个数组其实就是正在加载的class字节码,所以如果要字节码增强在这里就可以入手啦,甚至可以实现偷天换日.

你可能感兴趣的:(jvm,socket)