繁体   English   中英

使用JNI从本机方法返回null

[英]Returning null from native methods using JNI

我有一些本机代码返回一个jbyteArray(所以在Java端的字节[]),我想返回null。 但是,如果我只是返回0代替jbyteArray,我会遇到问题。

更多信息:主要逻辑是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代替jbyteArray是有效的,还是有另一个将null返回给Java的过程。 不幸的是,我在谷歌上没有运气。

谢谢!

编辑:添加了其他信息。

这是一个古老的问题,但我一分钟前也有这个问题......

你在问题中说:

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

我只是尝试了一个jintArray因为这是我的代码必须分配和返回的内容,除非发生错误(由与此主题无关​​的某些标准定义),在这种情况下它必须返回null结果。

碰巧返回NULL (定义为((void*)0) )完美地工作,并且在返回Java端时被解释为null 我没有发现任何性能下降。 除非我错过了任何返回0而没有void *演员不会改变任何东西。

所以我不认为这是你遇到的减速的原因。 NULL看起来很好,可以返回null

编辑

  • 我确认,返回值与表演无关。 我刚刚测试了一个相同的代码,在一侧返回一个空值,而它的对应方在另一方返回一个对象(一个jintArray )。 NULL性能类似,大小为0的jintArray ,以及静态分配的几KB的随机jintArray

  • 我也试过改变一个调用者类的字段的值,并且返回void,具有大致相同的性能。 非常慢一点,可能是由于捕获该字段并设置它所需的反射代码。

  • 所有这些测试都是在Android下进行的,而不是在Java标准下进行的 - 也许这就是为什么? (看评论):

    • 在HAXM下运行的API 17 x86仿真器
    • API 19,在相同条件下运行
    • 两个API 19物理设备 - 华硕平板电脑和Galaxy 5 - 在Dalvik下运行。

你的代码中存在一些不对称的东西:你永远不会决定要返回的对象的类型,除非返回“没有”。 显然env对象决定如何分配javaSrray ,那么为什么不让它返回某种空数组呢? 在jni和java之间进行编组时,可能需要以特殊方式处理返回的0。

您是否尝试过返回NULL引用?

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

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

编辑如上所述,您检查是否发生异常,但不清除它。 据我所知,这意味着它仍然被“抛出”在Java层中,因此您应该能够将其用作错误指示器; 那么函数返回什么并不重要。 实际上,根据文档,在抛出异常时调用除ExceptionClear()/ ExceptionDescribe()之外的JNI函数并不“安全”。 函数“慢”可能是由编写调试信息的ExceptionDescribe()函数引起的。

因此,如果我理解正确,这应该是一个行为良好的函数,在第一次发生错误时抛出异常,并在每次后续调用时返回NULL(直到'错误'被清除):

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环境。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM