是否可以使用sun.misc.Unsafe在没有JNI的情况下调用C函数?

Fin*_*man 22 c java java-native-interface jvm native-code

一段C/C++代码可以为JNI方法提供一个函数指针数组.但是有没有办法直接从Java代码内部(不使用JNI或类似代码)调用数组指针指向的函数?JNI以某种方式做了类似的事情,所以必须有办法.JNI是如何做到的?是通过sun.misc.Unsafe吗?即使不是,我们是否可以使用一些不安全的解决方法来获取执行此操作的JVM代码?

我当然不打算在商业上使用它.我甚至不是专业人士,我只是非常喜欢编码而且我最近一直在研究CUDA所以我想也许我可以尝试将所有东西混合在一起,但JNI调用的开销会破坏GPU加速代码的目的.

apa*_*gin 64

JNI慢吗?

JNI已经进行了很多优化,你应该先尝试一下.但它确实有一定的开销,详见细节.

如果本机函数很简单并且经常调用,则此开销可能很大.JDK有一个名为Critical Natives的私有API,可以减少调用不需要太多JNI功能的函数的开销.

重要的原住民

本机方法必须满足以下条件才能成为关键本机:

  • 必须是静态的不是同步的 ;
  • 参数类型必须是原始原始数组 ;
  • 实现不能调用JNI函数,即它不能分配Java对象或抛出异常;
  • 不应该运行很长时间,因为它在运行时阻止GC.

除了那个之外,关键本机的声明看起来像常规的JNI方法

  • 它始于JavaCritical_而不是Java_;
  • 它没有多余的JNIEnv*jclass参数;
  • Java数组以两个参数传递:第一个是数组长度,第二个是指向原始数组数据的指针.也就是说,不需要GetArrayElements和朋友打电话,你可以立即使用直接数组指针.

例如JNI方法

JNIEXPORT jint JNICALL
Java_com_package_MyClass_nativeMethod(JNIEnv* env, jclass klass, jbyteArray array) {
    jboolean isCopy;
    jint length = (*env)->GetArrayLength(env, array);
    jbyte* buf = (*env)->GetByteArrayElements(env, array, &isCopy);
    jint result = process(buf, length);
    (*env)->ReleaseByteArrayElements(env, array, buf, JNI_ABORT);
    return result;    
}
Run Code Online (Sandbox Code Playgroud)

会转向

JNIEXPORT jint JNICALL
JavaCritical_com_package_MyClass_nativeMethod(jint length, jbyte* buf) {
    return process(buf, length);
}
Run Code Online (Sandbox Code Playgroud)

从JDK 7开始,仅在HotSpot JVM中支持关键本机.此外,仅从已编译的代码调用"关键"版本.因此,您需要关键和标准实现才能使其正常工作.

此功能专为JDK内部使用而设计.没有公共规范或其他东西.您可能找到的唯一文档可能是对JDK-7013347的评论.

基准

此基准测试显示,当本机工作负载非常小时,关键本机可比常规JNI方法快几倍.方法越长,相对开销越小.

JNI呼叫的性能


PS JDK正在进行一项工作,以实现Native MethodHandles,它将作为JNI的更快替代品.但是,它不太可能出现在JDK 10之前.

  1. http://cr.openjdk.java.net/~jrose/panama/native-call-primitive.html
  2. http://mail.openjdk.java.net/pipermail/panama-dev/2015-December/000225.html