JVM中Instrumentation實現

想必很多人據說過javaagent,可是不多人據說Instrumentation,其實Instrumentation就是javaagent的實現機制,說到Instrumentation,就必須想了解java的attach機制,那就先說下attach的實現。 在此輸入圖片描述 你們進行jstack的時候,是否是常常看到兩個線程Signal DispatcherAttach Listener線程,可能不知道是幹嗎的吧,這兩個線程是實現attach的關鍵所在,其中前者是在jvm啓動的時候就會建立的後者只有接收過attach請求的時候vm纔會建立,顧名思義,Signal Dispatcher是分發信號的Attach Listener 是處理attach請求的,那麼二者有什麼關係呢,當咱們執行attach方法的時候,會向目標vm發出一個SIGQUIT 的信號,目標vm收到這個信號以後就會建立Attach Listener線程了,固然jvm保證了不會多建立。java

Attach機制說得簡單點就是提供A進程能夠連上B進程(固然是java進程),建立socket進行通訊,A經過發命令給B,B而後對命令進行截取從本身的vm中獲取信息發回給客戶端vm,可是並非隨便發指令都會處理的,那麼attach Listener接收哪些命令呢,以下所示:linux

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字節碼,因此若是要字節碼加強在這裏就能夠入手啦,甚至能夠實現偷天換日。api

若是在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也不妥)。jvm

相關文章
相關標籤/搜索