从Java App访问C ++内存

时间:2012-12-17 21:43:01

标签: java memory-management java-native-interface

我有C ++ App,它调用了一些java功能。我正在使用JNI。一切正常,但仍有一个小问题。在C ++ App中,我有一些巨大的数组。 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);
}

2 个答案:

答案 0 :(得分:3)

为此目的,在Java 1.4中引入了直接ByteBuffers。与Java一起的新类是corresponding JNI functions。您可以将本机数组包装在ByteBuffer(以及相应的IntBuffer等视图)中,并在不进行复制的情况下进行读写。

答案 1 :(得分:1)

您可以做的最好的事情是使用Get<PrimitiveType>ArrayElements routines。希望VM支持pinning

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;

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

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

如果您对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>,还有其他什么?)。但是我的想法是在JNI端构造一个NativeDoubleArrayProxy对象,并将指针转换为jlong。 getDouble()和getDoubles()的JNI实现实现了从C ++到Java代码的复制。

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

另请参阅:What is the 'correct' way to store a native pointer inside a Java object?