想必不少人聽(tīng)說(shuō)過(guò)javaagent,但是很少人聽(tīng)說(shuō)Instrumentation,其實(shí)Instrumentation就是javaagent的實(shí)現(xiàn)機(jī)制,說(shuō)到Instrumentation,就必須想了解java的attach機(jī)制,那就先說(shuō)下attach的實(shí)現(xiàn)。

大家進(jìn)行jstack的時(shí)候,是不是經(jīng)常看到兩個(gè)線程Signal Dispatcher和 Attach Listener線程,可能不知道是干嘛的吧,這兩個(gè)線程是實(shí)現(xiàn)attach的關(guān)鍵所在,其中前者是在jvm啟動(dòng)的時(shí)候就會(huì)創(chuàng)建的,后者只有接收過(guò)attach請(qǐng)求的時(shí)候vm才會(huì)創(chuàng)建,顧名思義,Signal Dispatcher是分發(fā)信號(hào)的, Attach Listener 是處理attach請(qǐng)求的,那么兩者有什么關(guān)系呢,當(dāng)我們執(zhí)行attach方法的時(shí)候,會(huì)向目標(biāo)vm發(fā)出一個(gè)SIGQUIT 的信號(hào),目標(biāo)vm收到這個(gè)信號(hào)之后就會(huì)創(chuàng)建Attach Listener線程了,當(dāng)然jvm保證了不會(huì)多創(chuàng)建。
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機(jī)制說(shuō)得簡(jiǎn)單點(diǎn)就是提供A進(jìn)程可以連上B進(jìn)程(當(dāng)然是java進(jìn)程),創(chuàng)建socket進(jìn)行通信,A通過(guò)發(fā)命令給B,B然后對(duì)命令進(jìn)行截取從自己的vm中獲取信息發(fā)回給客戶端vm,但是并不是隨便發(fā)指令都會(huì)處理的,那么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的實(shí)現(xiàn)其實(shí)主要使用了load這個(gè)指令,它用來(lái)實(shí)現(xiàn)讓target vm動(dòng)態(tài)加載agentlib,Instrumentation的實(shí)現(xiàn)在一個(gè)名為libinstrument.dylib的動(dòng)態(tài)lib庫(kù),linux下是libinstrument.so,它是基于jvmti接口實(shí)現(xiàn)的,因此在對(duì)其進(jìn)行l(wèi)oad的時(shí)候會(huì)創(chuàng)建一個(gè)agent實(shí)例,并往jvmti環(huán)境注冊(cè)一些回調(diào)方法,比如監(jiān)聽(tīng)類文件加載的事件,vm初始化完成事件等,執(zhí)行Agent_OnAttach,這里會(huì)創(chuàng)建一個(gè)Instrumentation實(shí)例并返回給用戶供大家擴(kuò)展Instrumentation,比如增加一些transform。并會(huì)執(zhí)行Instrumentation實(shí)例的loadClassAndCallAgentmain方法,該方法主要執(zhí)行agent的MF文件里定義的 Agent-Class類的agentmain方法,當(dāng)vm初始化完畢之后,會(huì)調(diào)用loadClassAndCallPremain方法,該方法主要執(zhí)行agent的MF文件里定義的 Agent-Class類的pre main方法。在類進(jìn)行加載的時(shí)候會(huì)調(diào)用Instrumentation的transform方法,可以看看參數(shù)里有個(gè)byte數(shù)組,這個(gè)數(shù)組其實(shí)就是正在加載的class字節(jié)碼,所以如果要字節(jié)碼增強(qiáng)在這里就可以入手啦,甚至可以實(shí)現(xiàn)偷天換日.
posted on 2013-04-12 22:38
你假笨 閱讀(2206)
評(píng)論(0) 編輯 收藏