2017-05-03 24 views
1

由于我想知道是否值得使用JNI来提高应用程序的性能,我想知道GetIntArrayElements的复杂程度是多少。它是否总是在C中分配一个新的基本数组,并复制原始Java数组中的所有元素,或者它以某种方式设法传递一个指针?JNI:GetIntArrayElements的时间总是线性的吗?

我想知道是否值得使用线性的算法JNI,例如,两个向量的逐点相乘。在GetIntArrayElements为线性的情况下,如果我们需要首先复制载体,则我认为使用C/C++的潜在性能提升将会丢失。

+2

您可以传递一个直接的字节缓冲区,它或多或少地像一个指针。但是我怀疑你会从使用JNI中获得很多收益。 Oracle的JVM有一个JIT,它发出高度优化的本机代码。如果有任何性能优势,它可能不会摊销互操作成本。当你有一些你可以在C中完成的东西时,JNI是非常有用的,但是在Java中不能完成,例如OpenGL。 –

+0

感谢您的评论! 你介意共享更多关于字节缓冲区的信息吗? (一个链接就足够了) 此外,你的评论意味着'GetIntArrayElements'总是线性的吗? –

回答

1

GetIntArrayElements有一个可选的引用参数isCopy。当虚拟机为您使用数据副本时,此参数将设置为JNI_TRUE。这个想法是,不同的虚拟机实现可能有不同的数组内存表示,也是与C期望的内存布局不兼容的。

通常,在Java和本机代码之间共享内存的最快方式是使用直接ByteBuffer(使用allocateDirect创建的那些)。这些缓冲区使用可从C/C++直接使用的底层内存块。

在Java中创建一个缓冲区,并用一些数据填充它:

public static void main(String[] args) { 
    byte[] ba = "Hello Wolrd!".getBytes(StandardCharsets.US_ASCII); 
    ByteBuffer bb = ByteBuffer.allocateDirect(ba.length + 1); // for terminator 
    bb.put(ba); 
    callCPP(bb); 
} 

private static native void callCPP(ByteBuffer bytes); 

再从C/C++,你可以用GetDirectBufferAddress(这是C++)得到字节的基本块的地址:

JNIEXPORT void JNICALL Java_Main_callCPP(JNIEnv *env, jclass, jobject buff) { 
    const char* str = (char*) env->GetDirectBufferAddress(buff); 
    printf(str); // Hello World! 
} 

使用ByteBuffer的缺点是不存在的数据抽象,像一类字段具有特定的类型,在字节缓冲器中的位置不。

+0

非常感谢您的回答。 'isCopy'部分独自回答了我原来的问题。 出于好奇的新问题:你可以使用'ByteBuffer'方法修改本地'C'实现中可以在'Java'中看到的东西吗? –

+1

@IvayloToskov它应该工作(这是整个想法),我只是试了一下,是的! :) –