1 JVMTI
JVMTI 全名JVM Tool Interface,是JVM暴露出来的一些供用户扩展的接口集合。JVMTI是基于事件驱动的,JVM每执行到一定的逻辑就会主动调用一些事件的回调接口,这些接口可以供开发者扩展自己的逻辑。
下面是JVMTI的一些回调接口
typedef struct {/* 50 : VM Initialization Event */
jvmtiEventVMInit VMInit; /* 51 : VM Death Event */
jvmtiEventVMDeath VMDeath; /* 52 : Thread Start */
jvmtiEventThreadStart ThreadStart;/* 53 : Thread End */
jvmtiEventThreadEnd ThreadEnd; /* 54 : Class File Load Hook */
jvmtiEventClassFileLoadHook ClassFileLoadHook; /* 55 : Class Load */
jvmtiEventClassLoad ClassLoad; /* 56 : Class Prepare */
jvmtiEventClassPrepare ClassPrepare;/* 57 : VM Start Event */
jvmtiEventVMStart VMStart;/* 58 : Exception */
jvmtiEventException Exception;/* 59 : Exception Catch */
jvmtiEventExceptionCatch ExceptionCatch; /* 60 : Single Step */
jvmtiEventSingleStep SingleStep;/* 61 : Frame Pop */
jvmtiEventFramePop FramePop;/* 62 : Breakpoint */
jvmtiEventBreakpoint Breakpoint; /* 63 : Field Access */
jvmtiEventFieldAccess FieldAccess;/* 64 : Field Modification */
jvmtiEventFieldModification FieldModification; /* 65 : Method Entry */
jvmtiEventMethodEntry MethodEntry;/* 66 : Method Exit */
jvmtiEventMethodExit MethodExit;/* 67 : Native Method Bind */
jvmtiEventNativeMethodBind NativeMethodBind;/* 68 : Compiled Method Load */
jvmtiEventCompiledMethodLoad CompiledMethodLoad;/* 69 : Compiled Method Unload */
jvmtiEventCompiledMethodUnload CompiledMethodUnload; /* 70 : Dynamic Code Generated */
jvmtiEventDynamicCodeGenerated DynamicCodeGenerated; /* 71 : Data Dump Request */
jvmtiEventDataDumpRequest DataDumpRequest;/* 72 */
jvmtiEventReserved reserved72;/* 73 : Monitor Wait */
jvmtiEventMonitorWait MonitorWait;/* 74 : Monitor Waited */
jvmtiEventMonitorWaited MonitorWaited;/* 75 : Monitor Contended Enter */
jvmtiEventMonitorContendedEnter MonitorContendedEnter;/* 76 : Monitor Contended Entered */
jvmtiEventMonitorContendedEntered MonitorContendedEntered;/* 77 */
jvmtiEventReserved reserved77;/* 78 */
jvmtiEventReserved reserved78; /* 79 */
jvmtiEventReserved reserved79; /* 80 : Resource Exhausted */
jvmtiEventResourceExhausted ResourceExhausted;/* 81 : Garbage Collection Start */
jvmtiEventGarbageCollectionStart GarbageCollectionStart;/* 82 : Garbage Collection Finish */
jvmtiEventGarbageCollectionFinish GarbageCollectionFinish;/* 83 : Object Free */
jvmtiEventObjectFree ObjectFree;/* 84 : VM Object Allocation */
jvmtiEventVMObjectAlloc VMObjectAlloc;
} jvmtiEventCallbacks;
1.1 jvmtiEventVMInit的回调函数
虚拟机在创建create_vm的时候,初始化了JVMTI的环境, JvmtiExport::post_vm_initialized(); 的方法中
void JvmtiExport::post_vm_initialized() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_INIT, ("JVMTI Trg VM init event triggered" ));
// can now enable events
JvmtiEventController::vm_init();
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->is_enabled(JVMTI_EVENT_VM_INIT)) {
EVT_TRACE(JVMTI_EVENT_VM_INIT, ("JVMTI Evt VM init event sent" ));
JavaThread *thread = JavaThread::current();
JvmtiThreadEventMark jem(thread);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventVMInit callback = env->callbacks()->VMInit;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread());
}
}
}
}
代码中调用了VMInit的回调函数
1.2 jvmtiEventClassFileLoadHook回调函数
钩子方法是jvmtiEventClassFileLoadHook 的方法,我们可以看代码:在classFileParser的文件中
instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name, Handle class_loader,Handle protection_domain, KlassHandle host_klass, GrowableArray<Handle>* cp_patches, symbolHandle& parsed_name,bool verify, TRAPS) {
……
if (JvmtiExport::should_post_class_file_load_hook()) {
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain,
&ptr, &end_ptr,
&cached_class_file_bytes,
&cached_class_file_length);
if (ptr != cfs->buffer()) {
// JVMTI agent has modified class file data.
// Set new class file stream using JVMTI agent modified
// class file data.
cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
set_stream(cfs);
}
}
…
}
在jvmtiexport::post_class_file_load_hook函数最后调用了post_to_env()函数
void post_to_env(JvmtiEnv* env, bool caching_needed) {
unsigned char *new_data = NULL;
jint new_len = 0;
JvmtiClassFileLoadEventMark jem(_thread, _h_name, _class_loader,
_h_protection_domain,
_h_class_being_redefined);
JvmtiJavaThreadEventTransition jet(_thread);
JNIEnv* jni_env = (JvmtiEnv::get_phase() == JVMTI_PHASE_PRIMORDIAL)?
NULL : jem.jni_env();
jvmtiEventClassFileLoadHook callback = env->callbacks()->ClassFileLoadHook;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jni_env,
jem.class_being_redefined(),
jem.jloader(), jem.class_name(),
jem.protection_domain(),
_curr_len, _curr_data,
&new_len, &new_data);
}
......
}
函数中调用了jvmtiEventClassFileLoadHook 的钩子回调函数,也就是刚才在结构体中定义的jvmtiEventCallbacks