JVM源码分析之javaagent原理完全解读
轉(zhuǎn)載地址:https://yq.aliyun.com/articles/2946?spm=5176.100239.yqblog1.45
摘要:?前言 本系列文章都是基于Hotspot/JDK源碼,從源碼角度來(lái)分析我們常見(jiàn)的JVM參數(shù),Java概念以及對(duì)應(yīng)的實(shí)現(xiàn)原理及玩法等,希望從根本上來(lái)理清Java知識(shí)點(diǎn),我們會(huì)不定期地分享這個(gè)系列的文章,這些文章可能源于最近碰到的問(wèn)題,也可能是同學(xué)們的提問(wèn),甚至有可能是我們突然想到的話題等,有些東西我們現(xiàn)在可能也不一定清楚,但是我們非常愿意花時(shí)間去了解清楚并分享給大家。
前言
本系列文章都是基于Hotspot/JDK源碼,從源碼角度來(lái)分析我們常見(jiàn)的JVM參數(shù),Java概念以及對(duì)應(yīng)的實(shí)現(xiàn)原理及玩法等,希望從根本上來(lái)理清Java知識(shí)點(diǎn),我們會(huì)不定期地分享這個(gè)系列的文章,這些文章可能源于最近碰到的問(wèn)題,也可能是同學(xué)們的提問(wèn),甚至有可能是我們突然想到的話題等,有些東西我們現(xiàn)在可能也不一定清楚,但是我們非常愿意花時(shí)間去了解清楚并分享給大家。
概述
本文重點(diǎn)講述javaagent的具體實(shí)現(xiàn),因?yàn)樗嫦虻氖俏覀僯ava程序員,而且agent都是用java編寫(xiě)的,不需要太多的c/c++編程基礎(chǔ),不過(guò)這篇文章里也會(huì)講到JVMTIAgent(c實(shí)現(xiàn)的),因?yàn)閖avaagent的運(yùn)行還是依賴于一個(gè)特殊的JVMTIAgent。
對(duì)于javaagent或許大家都聽(tīng)過(guò),甚至使用過(guò),常見(jiàn)的用法大致如下:
java -javaagent:myagent.jar=mode=test Test我們通過(guò)-javaagent來(lái)指定我們編寫(xiě)的agent的jar路徑(./myagent.jar)及要傳給agent的參數(shù)(mode=test),這樣在啟動(dòng)的時(shí)候這個(gè)agent就可以做一些我們想要它做的事了。
javaagent的主要的功能如下:
- 可以在加載java文件之前做攔截把字節(jié)碼做修改
- 可以在運(yùn)行期將已經(jīng)加載的類的字節(jié)碼做變更,但是這種情況下會(huì)有很多的限制,后面會(huì)詳細(xì)說(shuō)
- 還有其他的一些小眾的功能
- 獲取所有已經(jīng)被加載過(guò)的類
- 獲取所有已經(jīng)被初始化過(guò)了的類(執(zhí)行過(guò)了clinit方法,是上面的一個(gè)子集)
- 獲取某個(gè)對(duì)象的大小
- 將某個(gè)jar加入到bootstrapclasspath里作為高優(yōu)先級(jí)被bootstrapClassloader加載
- 將某個(gè)jar加入到classpath里供AppClassloard去加載
- 設(shè)置某些native方法的前綴,主要在查找native方法的時(shí)候做規(guī)則匹配
想象一下可以讓程序按照我們預(yù)期的邏輯去執(zhí)行,聽(tīng)起來(lái)是不是挺酷的。
JVMTI
JVMTI全稱JVM Tool Interface,是jvm暴露出來(lái)的一些供用戶擴(kuò)展的接口集合,JVMTI是基于事件驅(qū)動(dòng)的,JVM每執(zhí)行到一定的邏輯就會(huì)調(diào)用一些事件的回調(diào)接口(如果有的話),這些接口可以供開(kāi)發(fā)者去擴(kuò)展自己的邏輯。
比如說(shuō)我們最常見(jiàn)的想在某個(gè)類的字節(jié)碼文件讀取之后類定義之前能修改相關(guān)的字節(jié)碼,從而使創(chuàng)建的class對(duì)象是我們修改之后的字節(jié)碼內(nèi)容,那我們就可以實(shí)現(xiàn)一個(gè)回調(diào)函數(shù)賦給JvmtiEnv(JVMTI的運(yùn)行時(shí),通常一個(gè)JVMTIAgent對(duì)應(yīng)一個(gè)jvmtiEnv,但是也可以對(duì)應(yīng)多個(gè))的回調(diào)方法集合里的ClassFileLoadHook,這樣在接下來(lái)的類文件加載過(guò)程中都會(huì)調(diào)用到這個(gè)函數(shù)里來(lái)了,大致實(shí)現(xiàn)如下:
jvmtiEventCallbacks callbacks;jvmtiEnv * jvmtienv = jvmti(agent); jvmtiError jvmtierror; memset(&callbacks, 0, sizeof(callbacks));callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook;jvmtierror = (*jvmtienv)->SetEventCallbacks( jvmtienv, &callbacks,sizeof(callbacks));JVMTIAgent
JVMTIAgent其實(shí)就是一個(gè)動(dòng)態(tài)庫(kù),利用JVMTI暴露出來(lái)的一些接口來(lái)干一些我們想做但是正常情況下又做不到的事情,不過(guò)為了和普通的動(dòng)態(tài)庫(kù)進(jìn)行區(qū)分,它一般會(huì)實(shí)現(xiàn)如下的一個(gè)或者多個(gè)函數(shù):
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved);JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);- Agent_OnLoad函數(shù),如果agent是在啟動(dòng)的時(shí)候加載的,也就是在vm參數(shù)里通過(guò)-agentlib來(lái)指定,那在啟動(dòng)過(guò)程中就會(huì)去執(zhí)行這個(gè)agent里的Agent_OnLoad函數(shù)。
- Agent_OnAttach函數(shù),如果agent不是在啟動(dòng)的時(shí)候加載的,是我們先attach到目標(biāo)進(jìn)程上,然后給對(duì)應(yīng)的目標(biāo)進(jìn)程發(fā)送load命令來(lái)加載agent,在加載過(guò)程中就會(huì)調(diào)用Agent_OnAttach函數(shù)。
- Agent_OnUnload函數(shù),在agent做卸載的時(shí)候調(diào)用,不過(guò)貌似基本上很少實(shí)現(xiàn)它。
其實(shí)我們每天都在和JVMTIAgent打交道,只是你可能沒(méi)有意識(shí)到而已,比如我們經(jīng)常使用eclipse等工具對(duì)java代碼做調(diào)試,其實(shí)就利用了jre自帶的jdwp agent來(lái)實(shí)現(xiàn)的,只是由于eclipse等工具在沒(méi)讓你察覺(jué)的情況下將相關(guān)參數(shù)(類似-agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:61349)給自動(dòng)加到程序啟動(dòng)參數(shù)列表里了,其中agentlib參數(shù)就是用來(lái)跟要加載的agent的名字,比如這里的jdwp(不過(guò)這不是動(dòng)態(tài)庫(kù)的名字,而JVM是會(huì)做一些名稱上的擴(kuò)展,比如在linux下會(huì)去找libjdwp.so的動(dòng)態(tài)庫(kù)進(jìn)行加載,也就是在名字的基礎(chǔ)上加前綴lib,再加后綴.so),接下來(lái)會(huì)跟一堆相關(guān)的參數(shù),會(huì)將這些參數(shù)傳給Agent_OnLoad或者Agent_OnAttach函數(shù)里對(duì)應(yīng)的options參數(shù)。
javaagent
說(shuō)到j(luò)avaagent必須要講的是一個(gè)叫做instrument的JVMTIAgent(linux下對(duì)應(yīng)的動(dòng)態(tài)庫(kù)是libinstrument.so),因?yàn)榫褪撬鼇?lái)實(shí)現(xiàn)javaagent的功能的,另外instrument agent還有個(gè)別名叫JPLISAgent(Java Programming Language Instrumentation Services Agent),從這名字里也完全體現(xiàn)了其最本質(zhì)的功能:就是專門為java語(yǔ)言編寫(xiě)的插樁服務(wù)提供支持的。
instrument agent
instrument agent實(shí)現(xiàn)了Agent_OnLoad和Agent_OnAttach兩方法,也就是說(shuō)我們?cè)谟盟臅r(shí)候既支持啟動(dòng)的時(shí)候來(lái)加載agent,也支持在運(yùn)行期來(lái)動(dòng)態(tài)來(lái)加載這個(gè)agent,其中啟動(dòng)時(shí)加載agent還可以通過(guò)類似-javaagent:myagent.jar的方式來(lái)間接加載instrument agent,運(yùn)行期動(dòng)態(tài)加載agent依賴的是jvm的attach機(jī)制JVM Attach機(jī)制實(shí)現(xiàn),通過(guò)發(fā)送load命令來(lái)加載agent。
instrument agent的核心數(shù)據(jù)結(jié)構(gòu)如下:
struct _JPLISAgent {JavaVM * mJVM; /* handle to the JVM */JPLISEnvironment mNormalEnvironment; /* for every thing but retransform stuff */JPLISEnvironment mRetransformEnvironment;/* for retransform stuff only */jobject mInstrumentationImpl; /* handle to the Instrumentation instance */jmethodID mPremainCaller; /* method on the InstrumentationImpl that does the premain stuff (cached to save lots of lookups) */jmethodID mAgentmainCaller; /* method on the InstrumentationImpl for agents loaded via attach mechanism */jmethodID mTransform; /* method on the InstrumentationImpl that does the class file transform */jboolean mRedefineAvailable; /* cached answer to "does this agent support redefine" */jboolean mRedefineAdded; /* indicates if can_redefine_classes capability has been added */jboolean mNativeMethodPrefixAvailable; /* cached answer to "does this agent support prefixing" */jboolean mNativeMethodPrefixAdded; /* indicates if can_set_native_method_prefix capability has been added */char const * mAgentClassName; /* agent class name */char const * mOptionsString; /* -javaagent options string */ };struct _JPLISEnvironment {jvmtiEnv * mJVMTIEnv; /* the JVM TI environment */JPLISAgent * mAgent; /* corresponding agent */jboolean mIsRetransformer; /* indicates if special environment */ };這里解釋下幾個(gè)重要項(xiàng):
- mNormalEnvironment:主要提供正常的類transform及redefine功能的。
- mRetransformEnvironment:主要提供類retransform功能的。
- mInstrumentationImpl:這個(gè)對(duì)象非常重要,也是我們java agent和JVM進(jìn)行交互的入口,或許寫(xiě)過(guò)javaagent的人在寫(xiě)premain以及agentmain方法的時(shí)候注意到了有個(gè)Instrumentation的參數(shù),這個(gè)參數(shù)其實(shí)就是這里的對(duì)象。
- mPremainCaller:指向sun.instrument.InstrumentationImpl.loadClassAndCallPremain方法,如果agent是在啟動(dòng)的時(shí)候加載的,那該方法會(huì)被調(diào)用。
- mAgentmainCaller:指向sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain方法,該方法在通過(guò)attach的方式動(dòng)態(tài)加載agent的時(shí)候調(diào)用。
- mTransform:指向sun.instrument.InstrumentationImpl.transform方法。
- mAgentClassName:在我們javaagent的MANIFEST.MF里指定的Agent-Class。
- mOptionsString:傳給agent的一些參數(shù)。
- mRedefineAvailable:是否開(kāi)啟了redefine功能,在javaagent的MANIFEST.MF里設(shè)置Can-Redefine-Classes:true。
- mNativeMethodPrefixAvailable:是否支持native方法前綴設(shè)置,通樣在javaagent的MANIFEST.MF里設(shè)置Can-Set-Native-Method-Prefix:true。
- mIsRetransformer:如果在javaagent的MANIFEST.MF文件里定義了Can-Retransform-Classes:true,那將會(huì)設(shè)置mRetransformEnvironment的mIsRetransformer為true。
啟動(dòng)時(shí)加載instrument agent
正如『概述』里提到的方式,就是啟動(dòng)的時(shí)候加載instrument agent,具體過(guò)程都在InvocationAdapter.c的Agent_OnLoad方法里,簡(jiǎn)單描述下過(guò)程:
- 創(chuàng)建并初始化JPLISAgent
- 監(jiān)聽(tīng)VMInit事件,在vm初始化完成之后做下面的事情:
- 創(chuàng)建InstrumentationImpl對(duì)象
- 監(jiān)聽(tīng)ClassFileLoadHook事件
- 調(diào)用InstrumentationImpl的loadClassAndCallPremain方法,在這個(gè)方法里會(huì)去調(diào)用javaagent里MANIFEST.MF里指定的Premain-Class類的premain方法
- 解析javaagent里MANIFEST.MF里的參數(shù),并根據(jù)這些參數(shù)來(lái)設(shè)置JPLISAgent里的一些內(nèi)容
運(yùn)行時(shí)加載instrument agent
運(yùn)行時(shí)加載的方式,大致按照下面的方式來(lái)操作:
VirtualMachine vm = VirtualMachine.attach(pid); vm.loadAgent(agentPath, agentArgs);上面會(huì)通過(guò)jvm的attach機(jī)制來(lái)請(qǐng)求目標(biāo)jvm加載對(duì)應(yīng)的agent,過(guò)程大致如下:
- 創(chuàng)建并初始化JPLISAgent
- 解析javaagent里MANIFEST.MF里的參數(shù)
- 創(chuàng)建InstrumentationImpl對(duì)象
- 監(jiān)聽(tīng)ClassFileLoadHook事件
- 調(diào)用InstrumentationImpl的loadClassAndCallAgentmain方法,在這個(gè)方法里會(huì)去調(diào)用javaagent里MANIFEST.MF里指定的Agent-Class類的agentmain方法
instrument agent的ClassFileLoadHook回調(diào)實(shí)現(xiàn)
不管是啟動(dòng)時(shí)還是運(yùn)行時(shí)加載的instrument agent都關(guān)注著同一個(gè)jvmti事件---ClassFileLoadHook,這個(gè)事件是在讀取字節(jié)碼文件之后回調(diào)時(shí)用的,這樣可以對(duì)原來(lái)的字節(jié)碼做修改,那這里面究竟是怎樣實(shí)現(xiàn)的呢?
void JNICALL eventHandlerClassFileLoadHook( jvmtiEnv * jvmtienv, JNIEnv * jnienv, jclass class_being_redefined,jobject loader,const char* name,jobject protectionDomain,jint class_data_len,const unsigned char* class_data,jint* new_class_data_len,unsigned char** new_class_data) {JPLISEnvironment * environment = NULL;environment = getJPLISEnvironment(jvmtienv); /* if something is internally inconsistent (no agent), just silently return without touching the buffer */if ( environment != NULL ) {jthrowable outstandingException = preserveThrowable(jnienv); transformClassFile( environment->mAgent,jnienv, loader,name,class_being_redefined,protectionDomain,class_data_len,class_data,new_class_data_len,new_class_data,environment->mIsRetransformer);restoreThrowable(jnienv, outstandingException);} }先根據(jù)jvmtiEnv取得對(duì)應(yīng)的JPLISEnvironment,因?yàn)樯厦嫖乙呀?jīng)說(shuō)到其實(shí)有兩個(gè)JPLISEnvironment(并且有兩個(gè)jvmtiEnv),其中一個(gè)專門做retransform的,而另外一個(gè)用來(lái)做其他的事情,根據(jù)不同的用途我們?cè)谧?cè)具體的ClassFileTransformer的時(shí)候也是分開(kāi)的,對(duì)于作為retransform用的ClassFileTransformer我們會(huì)注冊(cè)到一個(gè)單獨(dú)的TransformerManager里。
接著調(diào)用transformClassFile方法,由于函數(shù)實(shí)現(xiàn)比較長(zhǎng),我這里就不貼代碼了,大致意思就是調(diào)用InstrumentationImpl對(duì)象的transform方法,根據(jù)最后那個(gè)參數(shù)來(lái)決定選哪個(gè)TransformerManager里的ClassFileTransformer對(duì)象們做transform操作。
private byte[]transform( ClassLoader loader,String classname,Class classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer,boolean isRetransformer) {TransformerManager mgr = isRetransformer?mRetransfomableTransformerManager :mTransformerManager;if (mgr == null) {return null; // no manager, no transform} else {return mgr.transform( loader,classname,classBeingRedefined,protectionDomain,classfileBuffer);}}public byte[]transform( ClassLoader loader,String classname,Class classBeingRedefined,ProtectionDomain protectionDomain,byte[] classfileBuffer) {boolean someoneTouchedTheBytecode = false;TransformerInfo[] transformerList = getSnapshotTransformerList();byte[] bufferToUse = classfileBuffer;// order matters, gotta run 'em in the order they were addedfor ( int x = 0; x < transformerList.length; x++ ) {TransformerInfo transformerInfo = transformerList[x];ClassFileTransformer transformer = transformerInfo.transformer();byte[] transformedBytes = null;try {transformedBytes = transformer.transform( loader,classname,classBeingRedefined,protectionDomain,bufferToUse);}catch (Throwable t) {// don't let any one transformer mess it up for the others.// This is where we need to put some logging. What should go here? FIXME}if ( transformedBytes != null ) {someoneTouchedTheBytecode = true;bufferToUse = transformedBytes;}}// if someone modified it, return the modified buffer.// otherwise return null to mean "no transforms occurred"byte [] result;if ( someoneTouchedTheBytecode ) {result = bufferToUse;}else {result = null;}return result;}以上是最終調(diào)到的java代碼,可以看到已經(jīng)調(diào)用到我們自己編寫(xiě)的javaagent代碼里了,我們一般是實(shí)現(xiàn)一個(gè)ClassFileTransformer類,然后創(chuàng)建一個(gè)對(duì)象注冊(cè)了對(duì)應(yīng)的TransformerManager里。
Class Transform的實(shí)現(xiàn)
這里說(shuō)的class transform其實(shí)是狹義的,主要是針對(duì)第一次類文件加載的時(shí)候就要求被transform的場(chǎng)景,在加載類文件的時(shí)候發(fā)出ClassFileLoad的事件,然后交給instrumenat agent來(lái)調(diào)用javaagent里注冊(cè)的ClassFileTransformer實(shí)現(xiàn)字節(jié)碼的修改。
Class Redefine的實(shí)現(xiàn)
類重新定義,這是Instrumentation提供的基礎(chǔ)功能之一,主要用在已經(jīng)被加載過(guò)的類上,想對(duì)其進(jìn)行修改,要做這件事,我們必須要知道兩個(gè)東西,一個(gè)是要修改哪個(gè)類,另外一個(gè)是那個(gè)類你想修改成怎樣的結(jié)構(gòu),有了這兩信息之后于是你就可以通過(guò)InstrumentationImpl的下面的redefineClasses方法去操作了:
public voidredefineClasses(ClassDefinition[] definitions)throws ClassNotFoundException {if (!isRedefineClassesSupported()) {throw new UnsupportedOperationException("redefineClasses is not supported in this environment");}if (definitions == null) {throw new NullPointerException("null passed as 'definitions' in redefineClasses");}for (int i = 0; i < definitions.length; ++i) {if (definitions[i] == null) {throw new NullPointerException("element of 'definitions' is null in redefineClasses");}}if (definitions.length == 0) {return; // short-circuit if there are no changes requested}redefineClasses0(mNativeAgent, definitions);}在JVM里對(duì)應(yīng)的實(shí)現(xiàn)是創(chuàng)建一個(gè)VM_RedefineClasses的VM_Operation,注意執(zhí)行它的時(shí)候會(huì)stop the world的:
jvmtiError JvmtiEnv::RedefineClasses(jint class_count, const jvmtiClassDefinition* class_definitions) { //TODO: add lockingVM_RedefineClasses op(class_count, class_definitions, jvmti_class_load_kind_redefine);VMThread::execute(&op);return (op.check_error()); } /* end RedefineClasses */這個(gè)過(guò)程我盡量用語(yǔ)言來(lái)描述清楚,不詳細(xì)貼代碼了,因?yàn)榇a量實(shí)在有點(diǎn)大:
- 挨個(gè)遍歷要批量重定義的jvmtiClassDefinition
- 然后讀取新的字節(jié)碼,如果有關(guān)注ClassFileLoadHook事件的,還會(huì)走對(duì)應(yīng)的transform來(lái)對(duì)新的字節(jié)碼再做修改
- 字節(jié)碼解析好,創(chuàng)建一個(gè)klassOop對(duì)象
- 對(duì)比新老類,并要求如下:
- 父類是同一個(gè)
- 實(shí)現(xiàn)的接口數(shù)也要相同,并且是相同的接口
- 類訪問(wèn)符必須一致
- 字段數(shù)和字段名要一致
- 新增或刪除的方法必須是private static/final的
- 可以修改方法
- 對(duì)新類做字節(jié)碼校驗(yàn)
- 合并新老類的常量池
- 如果老類上有斷點(diǎn),那都清除掉
- 對(duì)老類做jit去優(yōu)化
- 對(duì)新老方法匹配的方法的jmethodid做更新,將老的jmethodId更新到新的method上
- 新類的常量池的holer指向老的類
- 將新類和老類的一些屬性做交換,比如常量池,methods,內(nèi)部類
- 初始化新的vtable和itable
- 交換annotation的method,field,paramenter
- 遍歷所有當(dāng)前類的子類,修改他們的vtable及itable
上面是基本的過(guò)程,總的來(lái)說(shuō)就是只更新了類里內(nèi)容,相當(dāng)于只更新了指針指向的內(nèi)容,并沒(méi)有更新指針,避免了遍歷大量已有類對(duì)象對(duì)它們進(jìn)行更新帶來(lái)的開(kāi)銷。
Class Retransform的實(shí)現(xiàn)
retransform class可以簡(jiǎn)單理解為回滾操作,具體回滾到哪個(gè)版本,這個(gè)需要看情況而定,下面不管那種情況都有一個(gè)前提,那就是javaagent已經(jīng)要求要有retransform的能力了:
- 如果類是在第一次加載的的時(shí)候就做了transform,那么做retransform的時(shí)候會(huì)將代碼回滾到transform之后的代碼
- 如果類是在第一次加載的的時(shí)候沒(méi)有任何變化,那么做retransform的時(shí)候會(huì)將代碼回滾到最原始的類文件里的字節(jié)碼
- 如果類已經(jīng)被加載了,期間類可能做過(guò)多次redefine(比如被另外一個(gè)agent做過(guò)),但是接下來(lái)加載一個(gè)新的agent要求有retransform的能力了,然后對(duì)類做redefine的動(dòng)作,那么retransform的時(shí)候會(huì)將代碼回滾到上一個(gè)agent最后一次做redefine后的字節(jié)碼
我們從InstrumentationImpl的retransformClasses方法參數(shù)看猜到應(yīng)該是做回滾操作,因?yàn)槲覀冎恢付薱lass
public voidretransformClasses(Class<?>[] classes) {if (!isRetransformClassesSupported()) {throw new UnsupportedOperationException("retransformClasses is not supported in this environment");}retransformClasses0(mNativeAgent, classes);}不過(guò)retransform的實(shí)現(xiàn)其實(shí)也是通過(guò)redefine的功能來(lái)實(shí)現(xiàn),在類加載的時(shí)候有比較小的差別,主要體現(xiàn)在究竟會(huì)走哪些transform上,如果當(dāng)前是做retransform的話,那將忽略那些注冊(cè)到正常的TransformerManager里的ClassFileTransformer,而只會(huì)走專門為retransform而準(zhǔn)備的TransformerManager的ClassFileTransformer,不然想象一下字節(jié)碼又被無(wú)聲無(wú)息改成某個(gè)中間態(tài)了。
private:void post_all_envs() {if (_load_kind != jvmti_class_load_kind_retransform) {// for class load and redefine,// call the non-retransformable agentsJvmtiEnvIterator it;for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {if (!env->is_retransformable() && env->is_enabled(JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {// non-retransformable agents cannot retransform back,// so no need to cache the original class file bytespost_to_env(env, false);}}}JvmtiEnvIterator it;for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {// retransformable agents get all eventsif (env->is_retransformable() && env->is_enabled(JVMTI_EVENT_CLASS_FILE_LOAD_HOOK)) {// retransformable agents need to cache the original class file// bytes if changes are made via the ClassFileLoadHookpost_to_env(env, true);}}}javaagent的其他小眾功能
javaagent除了做字節(jié)碼上面的修改之外,其實(shí)還有一些小功能,有時(shí)候還是挺有用的
-
獲取所有已經(jīng)被加載的類
Class[] getAllLoadedClasses(); -
獲取所有已經(jīng)被初始化過(guò)了的類
Class[] getInitiatedClasses(ClassLoader loader); -
獲取某個(gè)對(duì)象的大小
long getObjectSize(Object objectToSize); -
將某個(gè)jar加入到bootstrapclasspath里優(yōu)先其他jar被加載
void appendToBootstrapClassLoaderSearch(JarFile jarfile); -
將某個(gè)jar加入到classpath里供appclassloard去加載
void appendToSystemClassLoaderSearch(JarFile jarfile); -
設(shè)置某些native方法的前綴,主要在找native方法的時(shí)候做規(guī)則匹配
void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
總結(jié)
以上是生活随笔為你收集整理的JVM源码分析之javaagent原理完全解读的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 当前火热的短视频,背后有着哪些黑科技技术
- 下一篇: JVMTM Tool Interface