本文档说明了Exception和ExceptionCatch事件
The exception field identifies the thrown exception object.
虽然它没有说明如何在运行期间比较它们(即比较Exception中提供的异常对应于ExceptionCatch中捕获的expcetion).换句话说,为
# java -version java version "1.7.0_85" OpenJDK Runtime Environment (IcedTea 2.6.1) (7u85-2.6.1-5ubuntu0.14.04.1) OpenJDK 64-Bit Server VM (build 24.85-b03,mixed mode)
直接比较jexception / jobject似乎并不总是如此.考虑监视Exception和ExceptionCatch事件的JVMTI代理(下面的源代码),还考虑抛出异常的后续Java天真示例(也包括源代码),最后您可以通过“make run”运行代理示例“使用给定的Makefile(包含在最后).
如果我使用OpenJDK 7运行该示例,它会给我以下结果:
# make run ... cb_Exception (exception=0x2ae6b8087be8) cb_ExceptionCatch (exception=0x2ae6b80859f8 vs last_exception=0x2ae6b8087be8) AreSameObject? = 0 cb_Exception (exception=0x2ae6b80859f8) cb_ExceptionCatch (exception=0x2ae6b807a388 vs last_exception=0x2ae6b80859f8) AreSameObject? = 0 cb_Exception (exception=0x2ae6b807a388) cb_ExceptionCatch (exception=0x2ae6b807a388 vs last_exception=0x2ae6b807a388) AreSameObject? = 1 cb_Exception (exception=0x2ae6b807a388) cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b807a388) AreSameObject? = 0 cb_Exception (exception=0x2ae6b8078108) cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108) AreSameObject? = 1 cb_Exception (exception=0x2ae6b8078108) cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108) AreSameObject? = 1 before doing work cb_Exception (exception=0x2ae6b8078108) cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108) AreSameObject? = 1 after doing work
如果我使用IBM的Java 1.7.0运行该示例,情况有点类似.
# make run ... cb_Exception (exception=0x7d78a0) cb_ExceptionCatch (exception=0x7d7950 vs last_exception=0x7d78a0) AreSameObject? = 1 cb_Exception (exception=0x7d7938) cb_ExceptionCatch (exception=0x7d7950 vs last_exception=0x7d7938) AreSameObject? = 0 cb_Exception (exception=0x7d7938) cb_ExceptionCatch (exception=0x7d79a8 vs last_exception=0x7d7938) AreSameObject? = 1 before doing work cb_Exception (exception=0x7d7a60) cb_ExceptionCatch (exception=0x7d7a98 vs last_exception=0x7d7a60) AreSameObject? = 0 after doing work
在OpenJDK中,请注意每个Exception都有一个相应的ExceptionCatch,但主Java代码之外有六个异常,我怀疑这些异常来自Java VM本身.请注意,异常的值在每对中都不相同.在第5次回调调用之后,异常的值似乎变得不变.这种情况在IBM的Java中有些类似,但引发的异常较少.作为来自评论的Chen Harel的建议,我已经存储了引发的异常,并通过IsSameObject JNI的方法与捕获的异常进行了比较,但JNI声称异常并不相同.
那么,Exception和ExceptionCatch可以在应用程序生命周期中识别异常吗?如果是,那么通过JVMTI或JNI比较异常的适当方法是什么?
agent.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <jni.h> #include <jvmti.h> #define CHECK_JVMTI_ERROR(x,call) \ { if (x != JVMTI_ERROR_NONE) { fprintf (stderr,"Error during %s in %s:%d\n",#call,__FILE__,__LINE__); } } /* Global static data */ static jvmtiEnv *jvmti; static jrawMonitorID ExtraeJ_AgentLock; jobject last_exception; static void JNICALL cb_Exception (jvmtiEnv *jvmti_env,JNIEnv* jni_env,jthread thread,jmethodID method,jlocation location,jobject exception,jmethodID catch_method,jlocation catch_location) { printf ("cb_Exception (exception=%p)\n",exception); last_exception = exception; } static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,jobject exception) { printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)\n" "AreSameObject? = %d\n",exception,last_exception,(*jni_env)->IsSameObject(jni_env,last_exception)); } JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm,char *options,void *reserved) { jint rc; jvmtiError r; jvmtiCapabilities capabilities; jvmtiEventCallbacks callbacks; /* Get JVMTI environment */ rc = (*vm)->GetEnv(vm,(void **)&jvmti,JVMTI_VERSION); if (rc != JNI_OK) { fprintf (stderr,"Error!: Unable to create jvmtiEnv,rc=%d\n",rc); return -1; } /* Get/Add JVMTI capabilities */ memset(&capabilities,sizeof(capabilities)); capabilities.can_generate_exception_events = 1; r = (*jvmti)->AddCapabilities(jvmti,&capabilities); CHECK_JVMTI_ERROR(r,AddCapabilities); /* Set callbacks and enable event notifications */ memset(&callbacks,sizeof(callbacks)); callbacks.Exception = &cb_Exception; callbacks.ExceptionCatch = &cb_ExceptionCatch; r = (*jvmti)->SetEventCallbacks(jvmti,&callbacks,sizeof(callbacks)); CHECK_JVMTI_ERROR(r,SetEventCallbacks); /* Exception events */ r = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION,NULL); CHECK_JVMTI_ERROR(r,SetEventNotificationMode); r = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_EVENT_EXCEPTION_CATCH,SetEventNotificationMode); return 0; } JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) { }
example.java
public class example { void except () throws Exception { throw new Exception ("new-exception"); } void do_work() { System.out.println ("before doing work"); try { except(); } catch (Exception e) {} System.out.println ("after doing work"); } public static void main (String [] args) { example e = new example(); e.do_work (); } }
Makefile文件
JAVA_JDK=/usr/lib/jvm/java-7-openjdk-amd64 all: libagent.so example.class libagent.so: agent.c gcc -shared -fPIC -DPIC agent.c -o libagent.so -I$(JAVA_JDK)/include example.class: example.java javac example.java run: libagent.so example.class java -agentpath:$(PWD)/libagent.so example
11月9日更新
正如Chen Harel建议的那样,我创建了一个对异常的全局引用. agent.c的修改版本如下,执行的输出如下所示.
agent.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <jni.h> #include <jvmti.h> #define CHECK_JVMTI_ERROR(x,exception); last_exception = (*jni_env)->NewGlobalRef (jni_env,exception); } static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,last_exception)); (*jni_env)->DeleteGlobalRef(jni_env,last_exception); } JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm,SetEventNotificationMode); return 0; } JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) { }
** make run **的输出
# make run ... cb_Exception (exception=0x2b13b0087c18) cb_ExceptionCatch (exception=0x2b13b0085a08 vs last_exception=0x2b13e4001608) AreSameObject? = 0 cb_Exception (exception=0x2b13b0085a08) cb_ExceptionCatch (exception=0x2b13b007a388 vs last_exception=0x2b13e4001610) AreSameObject? = 0 cb_Exception (exception=0x2b13b007a388) cb_ExceptionCatch (exception=0x2b13b007a388 vs last_exception=0x2b13e4001618) AreSameObject? = 1 cb_Exception (exception=0x2b13b007a388) cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a00) AreSameObject? = 0 cb_Exception (exception=0x2b13b0078108) cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a08) AreSameObject? = 1 cb_Exception (exception=0x2b13b0078108) cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a10) AreSameObject? = 1 before doing work cb_Exception (exception=0x2b13b0078108) cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a18) AreSameObject? = 1 after doing work
解决方法
测试两个jobject是否相同的方法是使用jni方法IsSameObject
如果要测试异常的类型,请使用GetObjectClass IsInstanceOf
编辑