java - 基于 jobject 调用 java 方法失败(无效引用?)

标签 java c++ java-native-interface

我有以下问题:

在我的 java 程序中,我调用了一个 native 函数,该函数在 C++ 中创建了“MyEventReceiver”类的对象,稍后在该 java 程序中,我调用了一个 native 函数,该函数调用了该对象的“测试”方法。在这个“测试”方法中,我想调用我用来调用第二个 native 函数的 java 对象的方法,但是一旦进行此调用,jvm 就会崩溃。

这是创建 MyEventReceiver 对象的 native 代码:

JNIEXPORT jlong JNICALL Java_irr4jEventReceiver_native_1createEventReceiver
  (JNIEnv *env, jobject obj){
    MyEventReceiver *rec = new MyEventReceiver(env, obj);
    return (long)rec;
}

这是我稍后在程序中用于调用该对象中的“测试”方法的 native 代码:

JNIEXPORT void JNICALL Java_irr4jEventReceiver_native_1testmethode
  (JNIEnv *env, jobject obj, jlong ptrrec){
  MyEventReceiver *rec = (MyEventReceiver*)ptrrec;
  rec->test();
}

这是 MyEventReceiver 类:

class MyEventReceiver : public IEventReceiver
{
public:
JNIEnv *myenv;
jobject receiverobj;
jclass SEventclass;
jobject eventobj;
jmethodID cid;

jclass cevrec;
jmethodID meth2;
public:    

    void test(){

         eventobj = myenv->AllocObject(SEventclass);                            
         eventobj = myenv->NewObject(SEventclass, cid);                       
         myenv->CallVoidMethod(receiverobj,meth2,eventobj); //this is the line that causes the crash

    }


    MyEventReceiver(JNIEnv *env, jobject obj)
    {

        this->myenv=env;    
        receiverobj = env->NewGlobalRef(obj);

        SEventclass = myenv->FindClass("SEvent");
        cid = myenv->GetMethodID(SEventclass,"<init>", "()V");   
        cevrec = myenv->FindClass("MyEventReceiver");                       
        meth2 =myenv->GetMethodID(cevrec, "OnEvent", "(LSEvent;)V");                     
        //test();
    }
};

如果我在构造函数的末尾调用方法“test”,它会起作用......只有当我稍后从 java 程序中进行调用时......我认为它与 jobject“receiverobj”有关“......似乎在一段时间后变得无效但我不知道为什么 ...我稍微剥离了代码...删除了一些调试代码。我正在创建的“eventobj”很好......我可以调用该对象的其他方法,methodIDs 也很好,只是行:

    myenv->CallVoidMethod(receiverobj,meth2,eventobj);

给我带来问题,我不知道为什么 :)

崩溃信息是:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x67d594f4, pid=5292, tid=2400
#
# JRE version: 7.0_21-b11
# Java VM: Java HotSpot(TM) Client VM (23.21-b01 mixed mode, sharing windows-x86 )
# Problematic frame:
# V  [jvm.dll+0xa94f4]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# G:\irr4jjava\irr4j\hs_err_pid5292.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

编辑:

感谢您到目前为止的帮助。我尝试使用全局引用和附加线程,但无法正常工作。我不确定我是否理解附加线程的内容......

我修改了第一个本地方法以创建对 jobject 的全局引用并将其传递给构造函数: JavaVM *jvm;

JNIEXPORT jlong JNICALL Java_irr4jEventReceiver_native_1createEventReceiver
  (JNIEnv *env, jobject obj){
      jobject recobj = env->NewGlobalRef(obj);
      env->GetJavaVM(&jvm);
      MyEventReceiver *rec = new MyEventReceiver(recobj);
      return (long)rec;
}   

在“MyReceiverObject”类中,我尝试附加线程但它仍然崩溃:

class MyEventReceiver : public IEventReceiver
{
public:
JNIEnv *myenv;
jobject receiverobj;
jclass SEventclass;
jobject eventobj;
jmethodID cid;
jclass cevrec;
jmethodID meth2;
public:

    void test(){

         jvm->AttachCurrentThread((void**)&myenv,NULL);

         eventobj = myenv->AllocObject(SEventclass);     //crash                        
                 eventobj = myenv->NewObject(SEventclass, cid);                      
         myenv->CallVoidMethod(receiverobj,meth2,eventobj);
    }


    MyEventReceiver(jobject obj)
    {

        jvm->AttachCurrentThread((void**)&myenv,NULL);      
        receiverobj=obj;

        SEventclass = myenv->FindClass("SEvent");
        cid = myenv->GetMethodID(SEventclass,"<init>", "()V");      
        cevrec = myenv->FindClass("MyEventReceiver");                       
        meth2 =myenv->GetMethodID(cevrec, "OnEvent", "(LSEvent;)V");        

        //test();
    }
};

最佳答案

您需要阅读 JNI 规范中有关全局引用的章节。您在 JNI 方法中传递的 jobject 仅在该方法的生命周期内有效。您需要将其转换为 GlobalRef,也许是 WeakGlobalRef,然后再将其存储在任何将比当前调用更有效的位置。

类似的事情适用于 JNIEnv 指针。它仅在传递给它的方法的持续时间内有效。如果您想在不同的线程中或稍后使用一个,您必须通过 AttachThread() 获取一个新的。

关于java - 基于 jobject 调用 java 方法失败(无效引用?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16745405/

相关文章:

java - 通过折叠所有元素来删除二维数组中的元素

c++ - 为什么不能在switch语句中声明变量?

java - -Djava.library.path 中的多个目录

Java 日期在使用简单日期格式的转换中不保留毫秒数

java - 正则表达式 - 否定类中的组

c++ - 在 C++ 中关闭列出的可执行文件,代码执行一次而不是连续扫描

c# - IP 多播 : How do I know someone is subscribed?

java - 使用 MinGW C++ 编译 64 位静态库以用于 Java (JNI)

安卓 JNI 错误

java - 即使不使用 put(),对象的属性也会在 Map 中更改吗?