代码之家  ›  专栏  ›  技术社区  ›  Dan

使用JNI从本机方法返回空值

  •  13
  • Dan  · 技术社区  · 15 年前

    我有一些本地代码返回JBYTARELY(在Java端上的字节[]),我想返回NULL。但是,如果只是返回0来代替jbytarray,我就会遇到问题。

    更多信息: 主要的逻辑是在Java中,原生方法用于将一些数据编码到字节流中。不要问..必须这样做。最近,本机代码必须做一些修改,现在运行速度非常慢。经过一些实验,包括在返回之前注释掉本机方法中的所有代码,结果是返回0会导致速度减慢。当返回一个实际的jbytearray时,一切都很好。

    我的代码的方法签名:

    在C++方面:

    extern "C" JNIEXPORT jbyteArray JNICALL Java_com_xxx_recode (JNIEnv* env, jclass java_this, jbyteArray origBytes, jobject message)
    

    Java方面:

    private static native byte[] recode(byte[] origBytes, Message message);
    

    本机代码如下所示:

    jbyteArray javaArray;
    if (error != ERROR) {
        // convert to jbyteArray
        javaArray = env->NewByteArray((jsize) message.size);
        env->SetByteArrayRegion(java_array, 0, message.size, reinterpret_cast<jbyte*>(message.buffer()));
        if (env->ExceptionOccurred()) {
            env->ExceptionDescribe();
            error = ERROR;
        }
    }
    if (error == ERROR) {
        return 0; // Does NOT work - doesn't crash, just slows everything down horrible.
    }
    else {
        return javaArray; // Works perfectly.
    }
    

    有人知道发生这种情况的原因吗?从原生方法返回NULL代替JBYTAREL是否有效,或者是否有另一个过程返回null返回Java。不幸的是,我在谷歌没有运气。

    谢谢!

    编辑:添加了附加信息。

    4 回复  |  直到 6 年前
        1
  •  -3
  •   Markus Lausberg    6 年前

    我不喜欢返回空值的解决方案。 如果可能的话,您应该返回一些空的实现,比如

    return new ArrayList();
    return new byte[0];
    return new EmptySomeObjectImpl();
    

    比你不担心nullpointerExceptions

    if (error == ERROR) {
        return env->NewByteArray(0);
    }
    

    编辑

    如果不想实现空对象,请尝试始终返回此值。

    if (error == ERROR) {
         return javaSrray; // Please test it and than return javaSrray always without if else
    }
    else {
        return javaSrray; // Works perfectly.
    }
    

    *** 编辑 ***

    经过几年的经验,我不得不不同意我的第一个答案。 空可以使人有知觉,我现在就去听什鲁布的回答。

    对于PUR Java代码,我仍然不喜欢NULL返回值,但是在JNI接口中,它可以实现更容易的错误处理。

        2
  •  4
  •   Shlublu    8 年前

    这是一个老问题,但我一分钟前就有了…

    你在问题中说:

    return 0; // Does NOT work - doesn't crash, just slows everything down horrible.
    

    实际上,我只是试了一下, jintArray 因为这是我的代码必须分配和返回的,除非发生错误(由与此主题无关的某些条件定义),在这种情况下,它必须返回一个空结果。

    碰巧回来了 NULL (定义为 ((void*)0) )工作完美,被解释为 null 当返回到Java端时。我没有注意到表演有任何退化。除非我错过了什么 0 没有 void * 演员阵容不会改变这一切。

    所以我不认为这是你遇到减速的原因。 无效的 看起来还不错 无效的 .

    编辑 :

    • 我确认,回报值与业绩无关。我刚刚测试了一个相同的代码,它在一侧返回一个空值,它的对应部分返回一个对象(a 金塔雷 )另一个。性能类似于 无效的 A 金塔雷 大小为0,随机 金塔雷 静态分配的几个kbs。

    • 我还尝试改变调用者类字段的值,并用大致相同的性能重新计算void。稍微慢一点,可能是因为捕获并设置该字段所需的反射代码。

    • 所有这些测试都是在Android下进行的,而不是Java标准的——也许这就是为什么?(见注释):

      • 在haxm下运行的api 17 x86仿真器
      • API 19 1,在相同条件下运行
      • 两个API 19物理设备-一个华硕平板电脑和一个Galaxy 5-在Dalvik下运行。
        3
  •  0
  •   xtofl Adam Rosenfield    15 年前

    你的代码有些不对称,这让我大吃一惊:你永远不会决定要返回的对象的类型,除非返回“Nothing”。显然是 env 对象决定如何分配 javaSrray ,那么为什么不要求它返回某种空数组呢?在JNI和Java之间封送处理时,可能需要以特殊的方式处理所返回的0个。

        4
  •  0
  •   Christoffer    15 年前

    是否尝试返回空引用?

    这是未测试的(目前没有JNI开发环境),但是您应该能够创建一个新的对空的全局引用,并像这样返回它:

    return (*env)->NewGlobalRef(env, NULL);
    

    编辑刚才所说的,检查是否发生了异常,但不要清除它。据我所知,这意味着它仍然被“抛出”在Java层中,所以您应该能够将它作为一个错误指示器,那么函数返回什么并不重要。事实上,根据文档,在引发异常时调用exceptionclear()/exceptiondescribe()以外的JNI函数并不“安全”。函数“慢”可能是由编写调试信息的exceptiondescribe()函数引起的。

    因此,如果我正确理解这一点,那么这应该是一个行为良好的函数,在第一次发生错误时引发异常,并在随后的每个调用中返回空值(直到清除“error”):

    if (error != ERROR) {
        jbyteArray javaArray = env->NewByteArray((jsize) message.size);
        env->SetByteArrayRegion(javaArray, 0, message.size, reinterpret_cast<jbyte*>(message.buffer()));
        if (env->ExceptionOccurred()) {
            error = ERROR;
            return 0;
        }
        return javaArray;
    } else {
        return env->NewGlobalRef(NULL);
    }
    

    同样,这是未测试的,因为我现在没有可用的JNI环境。

    推荐文章