jvm attach 机制

1 jvm与外部通信方式     bin/ 命令jmap,jstack,jinfo命令是如何获取到jvm内部的信息,jvisiualvm工具是如何获取某个目标jvm信息,然后展示到界面上。     jvm内部提供了一种机制叫attach机制,jvm外部可以通过attach机制连接目标jvm内部,获取内部jvm的信息,还可以动态加载agent,修改内部类等等 2 attach机制是什么     启动一个服务,启动java visualvm 可以看到    Attach Listener    Signal Dispatcher    两个线程:   jvm attach 机制 注意:signal dispatcher主要处理信号,它会默认启动,而attach listener线程不会随着jvm进程启动而启动,需要外部介入。 有两种方式可触发attach listener,第一种就是 jvm启动参数(没必要) StartAttachListener 参数,执行命令  java -XX:+StartAttachListener  第二种方式通过signal dispatcher方式启动 看一下VirtualMachine.attach(pid)的源码      public static VirtualMachine attach(String pid) throws AttachNotSupportedException, IOException {         if (pid == null) {             throw new NullPointerException("id cannot be null");         } else {             List providerList = AttachProvider.providers();             if (providerList.size() == 0) {                 throw new AttachNotSupportedException("no providers installed");             } else {                 AttachNotSupportedException ex = null;                 Iterator iterator = var1.iterator();                 while(iterator.hasNext()) {                     AttachProvider provider = (AttachProvider)iterator.next();                     try {                         return provider.attachVirtualMachine(pid);                     } catch (AttachNotSupportedException ex2) {                         ex = ex2;                     }                 }                 throw ex;             }         }     }   AttachProvider 调用attachVirtualMachine(pid)方法,遍历providerlist,找到匹配的attachprovider(LinuxAttachProvider)对象,在创建LinuxAttachProvider对象时,会往目标jvm发送某个信号,目标jvm收到信号后,只有signal dispatcher会处理该信号,singal dispatcher收到信号后,会触发 attach listener init方法,就会启动attach listener线程。(创建临时socket文件,创建进程id文件,然后匹配等等)   // Starts the Attach Listener thread void AttachListener() ::init{   EXCEPTION_MARK;   klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);   instanceKlassHandle klass (THREAD, k);   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);       const char thread_name[] = "Attach Listener";   Handle string = java_lang_String::create_from_str(thread_name, CHECK);       // Initialize thread_oop to put it into the system threadGroup   Handle thread_group (THREAD, Universe::system_thread_group());   JavaValue result(T_VOID);   JavaCalls::call_special(&result, thread_oop,                        klass,                        vmSymbols::object_initializer_name(),                        vmSymbols::threadgroup_string_void_signature(),                        thread_group,                        string,                        CHECK);       KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());   JavaCalls::call_special(&result,                         thread_group,                         group,                         vmSymbols::add_method_name(),                         vmSymbols::thread_void_signature(),                         thread_oop,             // ARG 1                         CHECK);       { MutexLocker mu(Threads_lock);     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);         // Check that thread and osthread were created     if (listener_thread == NULL || listener_thread->osthread() == NULL) {       vm_exit_during_initialization("java.lang.OutOfMemoryError",                                     "unable to create new native thread");     }         java_lang_Thread::set_thread(thread_oop(), listener_thread);     java_lang_Thread::set_daemon(thread_oop());         listener_thread->set_threadObj(thread_oop());     Threads::add(listener_thread);     Thread::start(listener_thread);   } }     3 Attach listener是如何工作的?      static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {   os::set_priority(thread, NearMaxPriority);     thread->record_stack_base_and_size();     if (AttachListener::pd_init() != 0) {     return;   }   AttachListener::set_initialized();     for (;;) {     AttachOperation* op = AttachListener::dequeue();     if (op == NULL) {       return;   // dequeue failed or shutdown     }     ResourceMark rm;     bufferedStream st;     jint res = JNI_OK;     // handle special detachall operation     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {       AttachListener::detachall();     } else {       // find the function to dispatch too       AttachOperationFunctionInfo* info = NULL;       for (int i=0; funcs[i].name != NULL; i++) {         const char* name = funcs[i].name;         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");         if (strcmp(op->name(), name) == 0) {           info = &(funcs[i]);           break;         }       }       // check for platform dependent attach operation       if (info == NULL) {         info = AttachListener::pd_find_operation(op->name());       }       if (info != NULL) {         // dispatch to the function that implements this operation         res = (info->func)(op, &st);       } else {         st.print("Operation %s not recognized!", op->name());         res = JNI_ERR;       }     }     // operation complete - send result and output to client     op->complete(res, &st);   } }     AttachOperation* AttachListener::dequeue() {   JavaThread* thread = JavaThread::current();   ThreadBlockInVM tbivm(thread);       thread->set_suspend_equivalent();   // cleared by handle_special_suspend_equivalent_condition() or   // java_suspend_self() via check_and_wait_while_suspended()       AttachOperation* op = LinuxAttachListener::dequeue();       // were we externally suspended while we were waiting?   thread->check_and_wait_while_suspended();       return op; }     LinuxAttachOperation* LinuxAttachListener::dequeue() {   for (;;) {     int s;         // wait for client to connect     struct sockaddr addr;     socklen_t len = sizeof(addr);     RESTARTABLE(::accept(listener(), &addr, &len), s);     if (s == -1) {       return NULL;      // log a warning?     }         // get the credentials of the peer and check the effective uid/guid     // - check with jeff on this.     struct ucred cred_info;     socklen_t optlen = sizeof(cred_info);     if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) {       int res;       RESTARTABLE(::close(s), res);       continue;     }     uid_t euid = geteuid();     gid_t egid = getegid();         if (cred_info.uid != euid || cred_info.gid != egid) {       int res;       RESTARTABLE(::close(s), res);       continue;     }         // peer credential look okay so we read the request     LinuxAttachOperation* op = read_request(s);     if (op == NULL) {       int res;       RESTARTABLE(::close(s), res);       continue;     } else {       return op;     }   } }   attach listener线程启动后,会不停的从队列获取AttachOperation, AttachListener::dequeue(); 调的是 LinuxAttachListener::dequeue();  底层逻辑等待请求,当获取请求后,创建套接字,读取数据,构建一个 LinuxAttachOperation对象 看一个例子   总结:   jvm attach 机制    
上一篇:领域设计:领域事件


下一篇:jmeter(十三)常见问题及解决方法