回调是否会在 JNI 函数内复制 jnienv、jinstance?

发布于 2025-01-09 13:02:09 字数 1200 浏览 0 评论 0原文

我传递给构建器的 lambda 被填充到 className 对象中,并定期(每小时)调用以刷新其他成员。第一次就被成功调用。我不确定 lambda 是否保留 envinstance 来合法调用反向 JNI 函数?

JNIEXPORT jint JNICALL
Java_com_company_app_ClassName_JniInit(JNIEnv *env, jobject instance){
  int data = 0;
  auto builder = new Builder(data,
        [env, instance]() -> std::string {
            std::string stringObj = populateData(env, instance); // This function makes a reverse JNI call to get data from a java function in the class
            return stringObj;
        }
    );

  std::shared_ptr<className> = builder->build(); 

  return 1;
}

我似乎收到了 SIGNAL 11 错误,SIGSEGV。这种分段错误是否可以以任何方式捕获,以便应用程序不会崩溃?

Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), failure addr 0x228 in tid 21785 (ClassName), pid 21573 (.company.app)

它似乎在 内的这一行崩溃populateData-

jstring data = (jstring)(env)->CallObjectMethod(instance, java函数名);

有没有办法在调用之前检查该函数是否会失败?我检查了 envpopulateData 中的 JNIEnv* 参数)是否为 NULL,但它不是,并且有一个有效的地址以及 instancepopulateData 中的 jinstance 参数)。

The lambda that I pass to builder is populated into className object, and called at regular intervals (every hour) of time to refresh the other members. It gets called the first time successfully. I'm not sure if the lambda retains env, instance to legally call the reverse JNI function?

JNIEXPORT jint JNICALL
Java_com_company_app_ClassName_JniInit(JNIEnv *env, jobject instance){
  int data = 0;
  auto builder = new Builder(data,
        [env, instance]() -> std::string {
            std::string stringObj = populateData(env, instance); // This function makes a reverse JNI call to get data from a java function in the class
            return stringObj;
        }
    );

  std::shared_ptr<className> = builder->build(); 

  return 1;
}

I seem to be getting a SIGNAL 11 error, SIGSEGV. Is this kind of segmentation fault catchable in any way, so the app doesn't crash?

Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x228 in tid 21785 (ClassName), pid 21573 (.company.app)

It seems to be crashing at this line inside populateData-

jstring data = (jstring)(env)->CallObjectMethod(instance, javaFunctionName);

Is there a way to check if this function will fail before calling it? I checked if env (JNIEnv* argument in populateData) is NULL, but its not, and has a valid address along with instance (jinstance argument in populateData).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

弃爱 2025-01-16 13:02:09

如果此函数异步执行某些操作,您将遇到 jobject 实例的问题。原因是在该函数启动之前,Java将该对象标记为具有额外的引用。当它返回时它会删除它。因此,在它返回后,如果 Java 代码中没有其他实例,则该对象可以被垃圾收集器清理。

可以通过在主线程上启动异步函数之前调用 NewGlobalRef(JNIEnv *env, jobject obj) 以及在 jobject 时回调结束时调用 DeleteGlobalRef 来修复此问题不再需要。

You'll have problems with jobject instance if this function does something asynchronously. The reason is that before this function is started, Java marks the object as having an extra reference. It removes that when it returns. So after it returns, the object can be cleaned up by the garbage collector if there's no other instances in the Java code.

This can be fixed by calling NewGlobalRef(JNIEnv *env, jobject obj) before starting the async function on the main thread, and calling DeleteGlobalRef at the end of the callback when jobject is no longer needed.

清风夜微凉 2025-01-16 13:02:09

为了回答这个问题,我发现了一种稍微不同的黑客方法。

不要复制 JNIEnvobject 或创建对它们的引用。一旦您的 JNI 函数超出范围,它们就会被删除。我不确定为什么复制不起作用(如果有人能回答这个问题,那就太好了)。或者,我使用 JavaVM* 来维护 jvm 的本地引用,您可以在 JNI_OnLoad 中执行此操作。

使用下面的函数,它会工作得很好。

JavaVM* jvm; // Initialise this in OnLoad

JNIEnv *getJNIEnv()
   {
        JNIEnv *env = nullptr;
        jint ret = jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
        if (ret == JNI_EDETACHED || !env)
        {
            env = nullptr;
        }
        return env;
   }

如果您需要类实例,则需要通过 JNIEnv 初始化它,但我的类使用静态方法,因此我只是使用 env->FindClass< 获取该类/code> 然后您可以执行 env->GetStaticMethodID 以及 env->CallStaticObjectMethod

To answer this question, I have found a slightly different kind of hack.

Don't copy the JNIEnv, and object or create references to them. They get deleted as soon as your JNI function goes out of scope. I'm not sure why copying doesn't work (if someone could answer this, that would be great). Alternatively, I've used JavaVM* to maintain a local reference of the jvm, you can do this in your JNI_OnLoad.

Use the function below, and it would work fine.

JavaVM* jvm; // Initialise this in OnLoad

JNIEnv *getJNIEnv()
   {
        JNIEnv *env = nullptr;
        jint ret = jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
        if (ret == JNI_EDETACHED || !env)
        {
            env = nullptr;
        }
        return env;
   }

If you need the class instance, you'll need to initialise it via JNIEnv, but I use a static method for my class, so I just fetched the class using env->FindClass and then you can do env->GetStaticMethodID along with env->CallStaticObjectMethod.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文