首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过JVMTI识别异常

通过JVMTI识别异常
EN

Stack Overflow用户
提问于 2015-11-02 15:52:24
回答 1查看 811关注 0票数 5

我正在使用JVMTI为Java应用程序编写一个测试工具。根据http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#Exception,我已经看到JVMTI检测何时抛出异常和何时捕获异常。此文档声明事件异常和ExceptionCatch。

异常字段标识抛出的异常对象。

虽然它没有说明如何在运行期间对它们进行比较(即比较异常中提供的异常对应于在ExceptionCatch中捕获的费用)。换句话说,对于

代码语言:javascript
复制
# 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时,它似乎并不总是正确的。考虑监视异常和ExceptionCatch事件的JVMTI代理(下面的源代码),还可以考虑随后引发异常的Java天真示例(也包括源代码),最后您可以通过给定的Makefile "make run“来运行这个示例(包括在最后)。

如果我使用OpenJDK 7运行这个例子,它会给出如下的结果:

代码语言:javascript
复制
# 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的Java1.7.0运行这个示例,情况就有点类似了。

代码语言:javascript
复制
# 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中,注意每个异常都有一个相应的ExceptionCatch,但是在主Java代码之外有六个异常,我怀疑这些异常来自Java本身。注意,异常的值在每对中都不是相同的。在第五次回调调用之后,异常的值似乎保持不变。这种情况在IBM的Java中有些相似,但例外较少。作为来自这些评论的陈哈雷尔的建议,我已经存储了引发的异常,并通过IsSameObject JNI的方法与捕获的异常进行了比较,但是JNI声称异常是不一样的。

那么,异常和ExceptionCatch可以在应用程序生命期内识别异常吗?如果是,通过JVMTI或JNI比较异常的合适方法是哪种?

agent.c

代码语言:javascript
复制
#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,
    JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location,
    jobject exception)
{
    printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)\n"
      "AreSameObject? = %d\n",
      exception,
      last_exception,
      (*jni_env)->IsSameObject(jni_env, exception, 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, 0, 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, 0, 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_ENABLE, 
      JVMTI_EVENT_EXCEPTION_CATCH, NULL);
    CHECK_JVMTI_ERROR(r, SetEventNotificationMode);

    return 0;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}

example.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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

更新9,11月

正如陈·哈雷尔所建议的那样,我在全球范围内提到了这一例外。agent.c的修改版本如下所示,执行的输出如下所示。

agent.c

代码语言:javascript
复制
#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 = (*jni_env)->NewGlobalRef (jni_env, exception);
}

static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,
    JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location,
    jobject exception)
{
    printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)\n"
      "AreSameObject? = %d\n",
      exception,
      last_exception,
      (*jni_env)->IsSameObject(jni_env, exception, last_exception));

    (*jni_env)->DeleteGlobalRef(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, 0, 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, 0, 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_ENABLE, 
      JVMTI_EVENT_EXCEPTION_CATCH, NULL);
    CHECK_JVMTI_ERROR(r, SetEventNotificationMode);

    return 0;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}

** make run的输出**

代码语言:javascript
复制
# 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
EN

回答 1

Stack Overflow用户

发布于 2015-11-04 00:04:23

jobject是一个C++指针,对堆的引用是在它下面处理的。如果你仔细想想,这更像是指向指针的指针。

测试两个jobjects是否相同的方法是使用jni方法IsSameObject

如果要测试异常的类型,请使用GetObjectClass + IsInstanceOf

编辑

注意,为了使jobject在方法之间有效,您必须使用jni NewGlobalRef方法为它们创建一个引用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33481612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档