4

我有调用一些 java 功能的 C++ 应用程序。我正在使用 JNI。一切正常,但仍然存在一个小问题。在 C++ 应用程序中,我有一些巨大的数组。Java App 也需要这些数据并返回一大堆结果。目前我只是复制数据(您可以在下面检查一些和平的代码)。如果我直接通过指针从 Java App 访问这些数组会更好。是否可以?我假设不是(因为 JVM),但在这种情况下,我必须向我的老板详细解释 :) 那么,是或否,以及如何或为什么?

jdoubleArray in2 = env->NewDoubleArray(1000);
jdouble *elems2 = (jdouble*)calloc(1000, sizeof(jdouble));
for(int i = 0; i < 1000; i++)
{
    elems2[i] = (jdouble)inputArray[i];
}
env->SetDoubleArrayRegion(in2, 0, 1000, elems2);
if(midCD != NULL)
{
    jdouble res1 = env->CallStaticDoubleMethod(cls, midCD, in2);
    double res1c = res1;
    printf("C++.Res1: %f\n", res1c);
}
4

2 回答 2

3

为此,Java 1.4 中引入了Direct ByteBuffers 。除了 Java 端的新类之外,还有相应的 JNI 函数。您可以将本机数组包装在 ByteBuffer(以及相应的 IntBuffer 等视图)中,并在不复制的情况下进行读写。

于 2012-12-18T00:41:15.610 回答
1

您能做的最好的事情是使用Get<PrimitiveType>ArrayElements 例程。希望VM支持固定

jdoubleArray in2 = env->NewDoubleArray(1000);
jboolean isCopy;
jdouble *elems2 = env->GetDoubleArrayElements(in2, &isCopy);
for(int i = 0; i < 1000; i++)
{
    elems2[i] = (jdouble)inputArray[i];
}
env->ReleaseDoubleArrayElements(in2, elems2, 0);
elems2 = NULL;

如果isCopyJNI_FALSE在调用 GetDoubleArrayElements() 之后,则没有复制。

编辑:重新阅读您的问题后,您可能需要考虑实施Archie 的想法。这取决于您的 Java 方法如何使用数据。如果 Java 方法不使用整个数组,或者不是一次全部使用,那么 Archie 使用本地访问器创建 C++ 数组的 Java 类包装器的解决方案可能是一个很好的解决方案。但是,如果 Java 方法需要所有数据,那么您可能只需要 GetDoubleArrayElements() 提供的将数据输入 VM 的最快方法。

如果您对 C++ 数组的某些元素进行更改并希望对 Java 副本进行相同的更改,那么SetDoubleArrayRegion()就可以发挥作用了。

EDIT2:我相信 Archie 指的是:

public class NativeDoubleArrayProxy {

    // This is the native `inputArray' pointer.
    private long p;

    private int length;

    private NativeDoubleArrayProxy(long p, int length) {
        this.p = p;
        this.length = length;
    }

    public int length() {
        return length;
    }

    public native double getDouble(int index);

    public native void getDoubles(int startingIndex, double[] out, int outOffset, int length);
}

确切的细节取决于你的类型inputArray(它是一个原始的 C 样式数组,还是一个std::vector<double>,其他的东西?)。但想法是NativeDoubleArrayProxy在 JNI 端构造一个对象,将指针转换为 a 传递给它jlong。getDouble() 和 getDoubles() 的 JNI 实现实现了从 C++ 到 Java 代码的复制。

当然,您需要非常小心以确保指针保持有效。

另请参阅:在 Java 对象中存储本机指针的“正确”方法是什么?

于 2012-12-17T23:43:47.920 回答