【问题标题】:JNI: Is GetIntArrayElements always linear in time?JNI:GetIntArrayElements 在时间上总是线性的吗?
【发布时间】:2017-05-03 14:37:18
【问题描述】:

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

我想知道将JNI 用于线性算法是否值得,例如两个向量的逐点乘法。如果GetIntArrayElements 是线性的,我猜如果我们需要先复制向量,使用C/C++ 的潜在性能提升将会丢失。

【问题讨论】:

  • 你可以传递一个直接的字节缓冲区,它或多或少像一个指针。但我怀疑您是否会从使用 JNI 中获益良多。 Oracle 的 JVM 有一个 JIT,它发出高度优化的本机代码。如果有任何性能优势,它可能不会摊销互操作的成本。 JNI 最适用于当您有一些可以在 C 中完成但在 Java 中无法完成的事情时,例如 OpenGL。
  • 感谢您的评论!您介意分享更多有关字节缓冲区的信息吗? (一个链接就足够了)此外,您的评论是否暗示GetIntArrayElements 总是线性的?

标签: java c performance java-native-interface time-complexity


【解决方案1】:

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

通常,在 Java 和本机代码之间共享内存的最快方式是直接使用 ByteBuffers(使用 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 的缺点是没有数据抽象,就像类的字段有特定的类型,字节缓冲区中的位置没有。

【讨论】:

  • 非常感谢您的回答。 isCopy 部分单独回答了我原来的问题。出于好奇的新问题:您能否使用ByteBuffer 方法修改在Java 中可见的本机C 实现中的内容?
  • @IvayloToskov 它应该可以工作(这就是整个想法),我刚刚尝试过,是的! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 2021-06-16
  • 2012-07-21
  • 2016-10-01
相关资源
最近更新 更多