Java 使用JNI从本机方法返回null

Java 使用JNI从本机方法返回null,java,c++,java-native-interface,Java,C++,Java Native Interface,我有一些本机代码,它返回一个jbyteArray(Java端的字节[]),我想返回null。但是,如果我只是返回0来代替jbyteArray,就会遇到问题 更多信息: 主要逻辑在Java中,本机方法用于将一些数据编码到字节流中。大学教师;我不问。。必须这样做。最近,本机代码不得不做了一些修改,现在运行速度非常慢。经过一些实验(包括在返回之前注释掉本机方法中的所有代码),结果表明返回0会导致速度减慢。返回实际的jbyteArray时,一切正常 我的代码的方法签名: 在C++方面: extern "

我有一些本机代码,它返回一个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.
}
return (*env)->NewGlobalRef(env, NULL);
jbyterarray-javaArray;
如果(错误!=错误){
//转换为jbyteArray
javaArray=env->NewByteArray((jsize)message.size);
env->SetByteArrayRegion(java_数组,0,message.size,reinterpret_cast(message.buffer());
如果(环境->例外发生()){
环境->例外描述();
错误=错误;
}
}
如果(错误==错误){
return 0;//不起作用-不会崩溃,只会减慢速度。
}
否则{
return javaArray;//工作正常。
}
有人知道发生这种情况的原因吗?从本机方法而不是jbyteArray返回NULL是否有效,或者是否有另一个过程将NULL返回到Java。不幸的是,我在谷歌上没有运气

谢谢


编辑:添加了额外的信息。

您的代码中有一些不对称的地方,这让我印象深刻:您从未决定要返回的对象的类型,除非返回“nothing”。显然,
env
对象决定如何分配
javaSrray
,那么为什么不要求它返回某种空数组呢?在jni和java之间进行封送处理时,可能需要以特殊方式处理返回的0。

是否尝试返回空引用

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

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.
}
return (*env)->NewGlobalRef(env, NULL);
也就是说,您检查是否发生异常,但不清除它。据我所知,这意味着它仍然被“抛出”到Java层,因此您应该能够将其用作错误指示器;那么函数返回什么并不重要。事实上,根据文档,在抛出异常时调用ExceptionClear()/ExceptionDescripte()以外的JNI函数并不“安全”。函数“慢”可能是由ExceptionDescripte()函数写入调试信息引起的

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

if(错误!=错误){
jbyteArray javaArray=env->NewByteArray((jsize)message.size);
env->SetByteArrayRegion(javaArray,0,message.size,reinterpret_cast(message.buffer());
如果(环境->例外发生()){
错误=错误;
返回0;
}
返回javaArray;
}否则{
返回env->NewGlobalRef(空);
}

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

这是一个老问题,但我一分钟前也有过这个问题

你在问题中说:

return 0; // Does NOT work - doesn't crash, just slows everything down horrible.
实际上,我只是尝试了一下,使用了
jintArray
,因为这是我的代码必须分配和返回的内容,除非发生错误(由一些与本主题无关的标准定义),在这种情况下,它必须返回空结果

恰好返回
NULL
(定义为
((void*)0)
)工作正常,返回到Java端时被解释为
NULL
。我没有注意到表演有任何下降。除非我错过了任何返回的
0
且没有
void*
cast的内容,否则我不会更改任何内容

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

编辑

  • 我确认,返回值与性能无关。我刚刚测试了同一个代码,它的一端返回空值,另一端返回对象(a
    jintArray
    )。对于大小为0的
    NULL
    、大小为0的
    jintArray
    和静态分配数KBs的随机
    jintArray
    ,性能类似

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

  • 所有这些测试都是在安卓系统下进行的,而不是在Java标准下进行的——也许这就是为什么?(见评论):

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

为什么返回0而不是数组?为什么不能简单地返回一个空数组?请提供更多关于本机库应该做什么的详细信息。您可以发布一些代码,至少是方法签名之类的吗?我特别希望Java接收“null”,而不是空字节数组。我可以重写Java代码来处理这个问题,但如果可能的话,我真的不愿意。我添加了方法签名。返回零确实有效,而且本身不会导致速度减慢。请提供更多信息。“请提供更多信息。”六年后?是的,我假设不是返回0(这似乎是可行的,即我在Java端得到一个空值,但出于某种奇怪的原因