使用JVM TI技术实现JVM监控

在JAVA单元测试中,需要监控单元测试的覆盖率,记录JAVA代码的执行过程,或者是需要动态插装字节码的应用程序中(例如AOP/IOC技术, 动态插装字节码的技术我将在下一篇的博客中介绍),我们可以使用JVM TI接口进行监控,本程序介绍一种监控JAVA代码的方法,注意:本程序不适合代码量很大的项目,会严重影响程序性能,如果需要开发高性能的监控代码,请参考我的另一篇博客

#include "stdafx.h" 
#include 
#include 
#include "windows.h"  
#include  

#include  

#include  

#include  

#include  

#include  

#include  

#include  

#include  
int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}
typedef jint (WINAPI *_CreateJavaVM)(JavaVM **, void **, void *); 
static jvmtiEnv *gb_jvmti = NULL;

static jvmtiCapabilities gb_capa;

static jrawMonitorID gb_lock;

 


static void   enter_critical_section(jvmtiEnv *jvmti)

{

    jvmtiError error;

    error = jvmti->RawMonitorEnter(gb_lock);

}

 


static void   exit_critical_section(jvmtiEnv *jvmti)

{

    jvmtiError error;

    error = jvmti->RawMonitorExit(gb_lock);

}

 


static void JNICALL callbackException(jvmtiEnv *jvmti_env, JNIEnv* env, jthread thr, jmethodID method, jlocation location, jobject exception, jmethodID catch_method, jlocation catch_location) 

{

            enter_critical_section(gb_jvmti); 

            {

                        char *name,*sig,*gsig;

                        jvmtiError  error  = gb_jvmti->GetMethodName(method, &name, &sig, &gsig);

                        if (error  != JVMTI_ERROR_NONE) 

                        {

                                printf("ERROR:GetMethodName!\n");

                                return;

                        }
                        printf("In Agent: Got an exception from Method: %s\n" ,name );

                       // if(strcmp(name,"main")==0)

                       // {

                         
                       // }

            }

            exit_critical_section(gb_jvmti); 

}

 


JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)

{

            jvmtiError error;

            jvmtiEventCallbacks callbacks;

 


            jint result = jvm->GetEnv((void **) &gb_jvmti, JVMTI_VERSION_1_0);

            if(result != JNI_OK || gb_jvmti==NULL)

            {

                        printf("ERROR: Unable to access JVMTI!");

                        return JNI_ERR;

            }

 


            memset(&gb_capa,0,sizeof(jvmtiCapabilities));

			gb_capa.can_signal_thread = 1;

			gb_capa.can_get_owned_monitor_info = 1;

			gb_capa.can_generate_method_entry_events = 1;

			gb_capa.can_generate_exception_events = 1;

			gb_capa.can_generate_vm_object_alloc_events = 1;

			gb_capa.can_tag_objects = 1;  

 


            //error = gb_jvmti->AddCapabilities(&gb_capa);

           /* if(error != JVMTI_ERROR_NONE)

            {

                        printf("ERROR: Can't get JVMTI capabilities");

                        return JNI_ERR;

            }*/

            jclass *classes;
			jint count;

			error = gb_jvmti->GetLoadedClasses(&count, &classes);
			if (error) {
				printf("ERROR: JVMTI GetLoadedClasses failed!\n");
			}
			for (int i = 0; i < count; i++) {
				char *sig;
				gb_jvmti->GetClassSignature(classes[i], &sig, NULL);
				if(strcmp(sig,"com/test/VMAttacher")>0)
				{
				   printf("cls sig=%s\n", sig);
				}
			}



            memset(&callbacks,0,sizeof(jvmtiEventCallbacks));

            callbacks.Exception = &callbackException;

 


            error = gb_jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));

            if(error != JVMTI_ERROR_NONE)

            {

                        printf("ERROR: Can't set jvmti callback!");

                        return JNI_ERR;

            }

 


            error = gb_jvmti->CreateRawMonitor("agent data", &gb_lock);

            if(error != JVMTI_ERROR_NONE)

            {

                        printf("ERROR: Can't create raw monitor!");

                        return JNI_ERR;

            }

 


 //   error = gb_jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_VM_INIT, (jthread)NULL);

		error = gb_jvmti->SetEventNotificationMode(JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION, (jthread)NULL);

 


         return JNI_OK;

}

 


JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{

				//
}


将以上代码编译DLL控件后,再使用javapath或者javalib参数指定该DLL控件作为JAVA Agent启动即可

你可能感兴趣的:(c)