JVM中Instrumentation實現

jopen 9年前發布 | 14K 次閱讀 JVM Java開發

想必不少人聽說過javaagent,但是很少人聽說Instrumentation,其實Instrumentation就是javaagent 的實現機制,說到Instrumentation,就必須想了解java的attach機制,那就先說下attach的實現。
JVM中Instrumentation實現
大家進行jstack的時候,是不是經常看到兩個線程Signal Dispatcher和Attach Listener線程,可能不知道是干嘛的吧,這兩個線程是實現attach的關鍵所在,其中前者是在jvm啟動的時候就會創建的,后者只有接收過attach請求的時候vm才會創建,顧名思義,Signal Dispatcher是分發信號的,Attach Listener 是處理attach請求的,那么兩者有什么關系呢,當我們執行attach方法的時候,會向目標vm發出一個SIGQUIT 的信號,目標vm收到這個信號之后就會創建Attach Listener線程了,當然jvm保證了不會多創建。

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類的premain方法。在類進行加載的時候會調用Instrumentation的transform方法,可以看看參數里有個byte數組,這個數組其實就是正在加載的class字節碼,所以如果要字節碼增強在這里就可以入手啦,甚至可以實現偷天換日。

如果在vm啟動過程中加載agent,那么會在vm初始化過程中先執行libinstrument.dylib里InvocationAdapter.c的Agent_OnLoad方法,該方法主要:實例化agent,解析agent的MF文件,將相關屬性取出來,并注冊JVMTI的一些回調函數,在vm初始化完成之后,會通過回調函數去實例化Instrumentation實現對象,設置ClassFileLoadHook函數,并調用Pre-Main指定類的premain方法。

如果在運行期通過attach api來load agent,那么會在收到load指令之后,會調用InvocationAdapter.c的Agent_OnAttach方法,其實現基本和Agent_OnLoad一致,只是會調用Agent-Class的agentmain方法,還有點不同就是對vm init事件沒有再關注(都運行期了,關注也沒用),而是直接對ClassFileLoad關注,也不會再調用Pre-Main指定的類的premain 方法(顧名思義,是在執行main方法之前執行的,所以運行期搞執行Pre-Main的class也不妥)。
來自:http://my.oschina.net/xianggao/blog/364494

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!