JVMTI之HelloWorld版權(quán)聲明:轉(zhuǎn)載時(shí)請(qǐng)以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明 JVMTI之HelloWorld
看了一些關(guān)于JVMTI的資料,對(duì)JVMTI的工作原理有了一個(gè)基本的了解,,從SUN給出的文檔來看,,JVMTI將是JVMPI和JVMDI等技術(shù)的替代品,并且建議用戶使用JVMTI,,而不是JVMPI或JVMDI,,因?yàn)樵谝院蟮?/span>JDK版本中,后兩種技術(shù)可能將不再支持了,。我們希望通過一個(gè)最簡單的HelloWorld程序來講述一下JVMTI編程的一些基本方式,。
1.原理和目標(biāo)。我們的目標(biāo)就是通過JVMTI技術(shù)來監(jiān)控JVM的一些行為,,具體到我們的這個(gè)例子中就是想監(jiān)控JVM中拋出的異常(Exception)事件,。為實(shí)現(xiàn)這一目標(biāo),我們需要編寫一個(gè)Agent動(dòng)態(tài)庫,,在JVM啟動(dòng)的時(shí)候?qū)⒃搫?dòng)態(tài)庫加載進(jìn)去,,在動(dòng)態(tài)庫中需要對(duì)異常(Exception)事件進(jìn)行注冊(cè),使得該類事件發(fā)生時(shí)能觸發(fā)我們編寫的函數(shù),,進(jìn)行相應(yīng)的處理,。所以我們例子中涉及到兩個(gè)部分,一部分是Java編寫的HelloWorld程序,,該程序中會(huì)拋出一個(gè)異常事件,;另一部分是C語言編寫的Agent動(dòng)態(tài)庫,用來監(jiān)控JVM的行為,。
2.HelloWorld程序,。這是一個(gè)很簡單的java 程序,在main函數(shù)中打印一條"HelloWorld"字符串,,并拋除一個(gè)Exception異常,。如下:
3.Agent動(dòng)態(tài)庫,。Agent動(dòng)態(tài)庫在window下為dll文件,在Linux/Unix為so文件,,其編寫過程非常簡單: 首先,,在代碼文件中加入”jvmti.h”頭文件,該文件包含在{JDK1.5主目錄}\inlcude目錄下,,它包含了我們所需要用到的一些變量和函數(shù)的定義,。如果編譯時(shí)找不到該頭文件,則應(yīng)該將“{JDK1.5主目錄}\inlcude”和“{JDK1.5主目錄}\inlcude\win32”加入到頭文件的搜索路徑中,。 其次,,實(shí)現(xiàn)Agent_OnLoad()和Agent_OnUnload()方法。Agent_Onload()方法在Agent被加載時(shí)調(diào)用,,我們需要在該函數(shù)中完成變量的初始化,,監(jiān)控事件的注冊(cè)等操作,從而使得當(dāng)某類事件發(fā)生時(shí),,JVM能夠通知該Agent,。Agent_Unload()方法在Agent被卸載時(shí)調(diào)用,用來釋放之前申請(qǐng)的內(nèi)存空間,,防止內(nèi)存泄漏,。我們首先需要?jiǎng)?chuàng)建一個(gè)callbackException()函數(shù),并通過SetEventCallbacks()方法將將該函數(shù)進(jìn)行注冊(cè),,使得當(dāng)捕獲到Exception事件時(shí),,能自動(dòng)回調(diào)該函數(shù): callbacks.Exception = &callbackException; error = gb_jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); 另外,我們需要通過SetEventNotificationMode()方法來向JVM預(yù)定Exception事件的通知,,讓JVM知道Agent對(duì)該類事件感興趣: error= gb_jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION, (jthread)NULL); 這樣,,當(dāng)JVM運(yùn)行過程發(fā)生Exception事件時(shí),callbackException()函數(shù)就會(huì)被調(diào)用,,我們可以在該函數(shù)中完成自己的一些操作,。在callbackException()函數(shù)中,我們會(huì)判斷捕獲到的Exception是從哪個(gè)方法中拋出的,,如果是“main”方法的話,,就打印出一行字符串: printf("In Agent: Got an exception from Method: %s\n" ,name ); 下面是Agent動(dòng)態(tài)庫的代碼:
4.編譯執(zhí)行。我是用VC6來編譯Agent動(dòng)態(tài)庫的,,在VC6種創(chuàng)建一個(gè)Win32動(dòng)態(tài)連接庫項(xiàng)目,,取名為MyAgentDll,然后將MyAgent.cpp文件加入該項(xiàng)目,。選擇“工具->選擇->目錄”,,然后將“{JDK1.5主目錄}\inlcude”和“{JDK1.5主目錄}\inlcude\win32加入到“inlcude files”目錄中。然后編譯構(gòu)建MyAgentDll.dll即可,。 因?yàn)?/span>JVMTI是JDK1.5中加入的一項(xiàng)新功能,,所以請(qǐng)先確認(rèn)你所使用的JDK版本: #java -version 編譯Sample.java。進(jìn)入Sample所在目錄,,在命令行執(zhí)行如下命令: # javac Sample.java 執(zhí)行Sample,。將MyAgentDll.dll拷貝到Sample.java所在目錄,用如下命令執(zhí)行: # java -agentpath:e:\work\jvmit\MyAgentDll.dll Sample 如果一切順利的話,,應(yīng)該看到如下結(jié)果: 其中,,“In Agent: Got an exception from Method: main”是Agent打印出來的,其他兩行是Sample.java打印出來的,。
5.結(jié)束語,。我們上面描述的只是一個(gè)非常簡單的JVMTI編程的例子,也是在別人代碼的基礎(chǔ)上修修改改得到的,,它基本上說明了JVMTI編程的大致框架,,如果在其基礎(chǔ)上進(jìn)行一些擴(kuò)充和豐富,就可以做出一些很有用的小工具,。目前一些非常著名的程序性能分析工具,,如JProbe, JRockit, Optimizeit等,雖然不知道其具體的技術(shù)細(xì)節(jié),,但猜想應(yīng)該也是采用了類似的實(shí)現(xiàn)機(jī)制,。 |
|