成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JVM源碼分析之Attach機制實現完全解讀

開發 后端
那Attach機制是什么?說簡單點就是jvm提供一種jvm進程間通信的能力,能讓一個進程傳命令給另外一個進程,并讓它執行內部的一些操作。

Attach是什么

在講這個之前,我們先來點大家都知道的東西,當我們感覺線程一直卡在某個地方,想知道卡在哪里,首先想到的是進行線程dump,而常用的命令是jstack ,我們就可以看到如下線程棧了

大家是否注意過上面圈起來的兩個線程,”Attach Listener”和“Signal Dispatcher”,這兩個線程是我們這次要講的Attach機制的關鍵,先偷偷告訴各位,其實Attach Listener這個線程在jvm起來的時候可能并沒有的,后面會細說。

那Attach機制是什么?說簡單點就是jvm提供一種jvm進程間通信的能力,能讓一個進程傳命令給另外一個進程,并讓它執行內部的一些操作,比如說我們為了讓另外一個jvm進程把線程dump出來,那么我們跑了一個jstack的進程,然后傳了個pid的參數,告訴它要哪個進程進行線程dump,既然是兩個進程,那肯定涉及到進程間通信,以及傳輸協議的定義,比如要執行什么操作,傳了什么參數等

Attach能做些什么

總結起來說,比如內存dump,線程dump,類信息統計(比如加載的類及大小以及實例個數等),動態加載agent(使用過btrace的應該不陌生),動態設置vm flag(但是并不是所有的flag都可以設置的,因為有些flag是在jvm啟動過程中使用的,是一次性的),打印vm flag,獲取系統屬性等,這些對應的源碼(AttachListener.cpp)如下 

  1. static AttachOperationFunctionInfo funcs[] = {  
  2.   { "agentProperties",  get_agent_properties },  
  3.   { "datadump",         data_dump },  
  4.   { "dumpheap",         dump_heap },  
  5.   { "load",             JvmtiExport::load_agent_library },  
  6.   { "properties",       get_system_properties },  
  7.   { "threaddump",       thread_dump },  
  8.   { "inspectheap",      heap_inspection },  
  9.   { "setflag",          set_flag },  
  10.   { "printflag",        print_flag },  
  11.   { "jcmd",             jcmd },  
  12.   { NULL,               NULL }  
  13. }; 

后面是命令對應的處理函數。

Attach在jvm里如何實現的

Attach Listener線程的創建

前面也提到了,jvm在啟動過程中可能并沒有啟動Attach Listener這個線程,可以通過jvm參數來啟動,代碼 (Threads::create_vm)如下: 

  1. if (!DisableAttachMechanism) {  
  2.    if (StartAttachListener || AttachListener::init_at_startup()) {  
  3.      AttachListener::init();  
  4.    }  
  5.  }  
  6. ool AttachListener::init_at_startup() {  
  7.  if (ReduceSignalUsage) {  
  8.    return true;  
  9.  } else {  
  10.    return false;  
  11.  } 

其中DisableAttachMechanism,StartAttachListener ,ReduceSignalUsage均默認是false(globals.hpp) 

  1. product(bool, DisableAttachMechanism, false,                         
  2.           "Disable mechanism that allows tools to Attach to this VM”)     
  3. product(bool, StartAttachListener, false,                                
  4.            "Always start Attach Listener at VM startup")    
  5. product(bool, ReduceSignalUsage, false,                                    
  6.            "Reduce the use of OS signals in Java and/or the VM”) 

因此AttachListener::init()并不會被執行,而Attach Listener線程正是在此方法里創建的

既然在啟動的時候不會創建這個線程,那么我們在上面看到的那個線程是怎么創建的呢,這個就要關注另外一個線程“Signal Dispatcher”了,顧名思義是處理信號的,這個線程是在jvm啟動的時候就會創建的,具體代碼就不說了。

下面以jstack的實現來說明觸發Attach這一機制進行的過程,jstack命令的實現其實是一個叫做JStack.java的類,查看jstack代碼后會走到下面的方法里

請注意VirtualMachine.Attach(pid);這行代碼,觸發Attach pid的關鍵,如果是在linux下會走到下面的構造函數

這里要解釋下代碼了,首先看到調用了createAttachFile方法在目標進程的cwd目錄下創建了一個文件/proc//cwd/.Attach_pid,這個在后面的信號處理過程中會取出來做判斷(為了安全),另外我們知道在linux下線程是用進程實現的,在jvm啟動過程中會創建很多線程,比如我們上面的信號線程,也就是會看到很多的pid(應該是LWP),那么如何找到這個信號處理線程呢,從上面實現來看是找到我們傳進去的pid的父進程,然后給它的所有子進程都發送一個SIGQUIT信號,而jvm里除了信號線程,其他線程都設置了對此信號的屏蔽,因此收不到該信號,于是該信號就傳給了“Signal Dispatcher”,在傳完之后作輪詢等待看目標進程是否創建了某個文件,AttachTimeout默認超時時間是5000ms,可通過設置系統變量sun.tools.Attach.AttachTimeout來指定,下面是Signal Dispatcher線程的entry實現

當信號是SIGBREAK(在jvm里做了#define,其實就是SIGQUIT)的時候,就會觸發

AttachListener::is_init_trigger()的執行

一開始會判斷當前進程目錄下是否有個.Attach_pid文件(前面提到了),如果沒有就會在/tmp下創建一個/tmp/.Attach_pid,當那個文件的uid和自己的uid是一致的情況下(為了安全)再調用init方法

此時水落石出了,看到創建了一個線程,并且取名為Attach Listener。再看看其子類LinuxAttachListener的init方法

看到其創建了一個監聽套接字,并創建了一個文件/tmp/.java_pid,這個文件就是客戶端之前一直在輪詢等待的文件,隨著這個文件的生成,意味著Attach的過程圓滿結束了。

Attach listener接收請求

看看它的entry實現Attach_listener_thread_entry

從代碼來看就是從隊列里不斷取AttachOperation,然后找到請求命令對應的方法進行執行,比如我們一開始說的jstack命令,找到 { “threaddump”, thread_dump }的映射關系,然后執行thread_dump方法

再來看看其要調用的AttachListener::dequeue(), 

  1. AttachOperation* AttachListener::dequeue() {  
  2.   JavaThread* thread = JavaThread::current();  
  3.   ThreadBlockInVM tbivm(thread);  
  4.   thread->set_suspend_equivalent();  
  5.   // cleared by handle_special_suspend_equivalent_condition() or  
  6.   // java_suspend_self() via check_and_wait_while_suspended()  
  7.   AttachOperation* op = LinuxAttachListener::dequeue();  
  8.   // were we externally suspended while we were waiting?  
  9.   thread->check_and_wait_while_suspended();  
  10.   return op;  

最終調用的是LinuxAttachListener::dequeue(),

我們看到如果沒有請求的話,會一直accept在那里,當來了請求,然后就會創建一個套接字,并讀取數據,構建出LinuxAttachOperation返回并執行。

整個過程就這樣了,從Attach線程創建到接收請求,處理請求。 

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2017-01-12 14:52:03

JVMFinalRefere源碼

2017-01-11 14:02:32

JVM源碼內存

2017-01-11 14:19:26

JVM源碼All

2010-09-26 16:55:31

JVM學習筆記

2024-09-06 09:37:45

WebApp類加載器Web 應用

2023-10-31 16:00:51

類加載機制Java

2017-02-27 11:48:58

JVM源碼分析Java

2020-07-21 14:19:18

JVM編程語言

2021-11-11 17:40:08

WatchdogAndroid源碼分析

2022-05-19 07:09:29

機制沙箱安全JVM

2024-10-31 09:24:42

2021-03-11 08:10:48

JVM對象的創建School

2017-01-11 22:51:39

2011-06-23 13:10:39

Python 對象機制

2022-09-23 08:02:42

Kafka消息緩存

2011-05-26 10:05:48

MongoDB

2022-07-19 20:04:31

NAPI模塊鴻蒙

2012-05-31 02:54:07

HadoopJava

2012-09-20 10:07:29

Nginx源碼分析Web服務器

2023-02-26 08:42:10

源碼demouseEffect
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 黄色在线免费观看 | 亚洲一区二区三区在线播放 | 午夜精品视频 | 91在线播| 美女一级毛片 | 国产在线视频一区 | 亚洲综合一区二区三区 | 玖玖在线免费视频 | 成人超碰在线 | 欧美久久精品一级c片 | 亚洲一区二区视频 | 日本一道本视频 | 欧美日韩一区二区视频在线观看 | 亚洲一区二区三区视频 | 中文天堂在线观看 | 欧美日韩国产一区二区 | 污免费网站 | 成人精品一区二区三区 | 一区二区三区视频免费看 | 国产蜜臀 | 亚洲 中文 欧美 日韩 在线观看 | 国产网站在线免费观看 | 国产精品久久久久久久久久免费看 | 欧美电影在线观看网站 | 国产欧美视频一区二区三区 | 国产精品毛片一区二区三区 | 欧美成人一区二区三区 | 精品日韩| 99免费看 | 91免费在线视频 | 日本三级日产三级国产三级 | 国产一区二区三区视频 | 午夜电影福利 | 精品毛片| 亚洲精品91 | 精品视频一二区 | 天天插天天操 | 日韩精品久久一区二区三区 | 在线一区 | 亚洲第一av| 91日日 |