Is it possible to use sun.misc.Unsafe to call C functions without JNI?

后端 未结 2 909
一生所求
一生所求 2020-12-02 13:27

A piece of C/C++ code could provide a JNI method with an array of function pointers. But is there a way to call to the stack the functions that array\'s pointers are pointin

2条回答
  •  半阙折子戏
    2020-12-02 14:26

    Is JNI that slow?

    JNI has already been optimized a lot, you should give it a try first. But it indeed has certain overhead, see details.

    This overhead can be significant if a native function is simple and is called frequently. JDK has a private API called Critical Natives to reduce overhead of calling functions that do not require much of JNI functionality.

    Critical Natives

    A native method must satisfy the following conditions to become a critical native:

    • must be static and not synchronized;
    • argument types must be primitive or primitive arrays;
    • implementation must not call JNI functions, i.e. it cannot allocate Java objects or throw exceptions;
    • should not run for a long time, since it will block GC while running.

    The declaration of a critical native looks like a regular JNI method, except that

    • it starts with JavaCritical_ instead of Java_;
    • it does not have extra JNIEnv* and jclass arguments;
    • Java arrays are passed in two arguments: the first is an array length, and the second is a pointer to raw array data. That is, no need to call GetArrayElements and friends, you can instantly use a direct array pointer.

    E.g. a JNI method

    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;    
    }
    

    will turn to

    JNIEXPORT jint JNICALL
    JavaCritical_com_package_MyClass_nativeMethod(jint length, jbyte* buf) {
        return process(buf, length);
    }
    

    Critical natives are supported only in HotSpot JVM starting from JDK 7. Moreover, "critical" version is called only from compiled code. Therefore you need both critical and standard implementation to make this work correctly.

    This feature was designed for internal use in JDK. There is no public specification or something. Probably the only documentation you may find is in the comments to JDK-7013347.

    Benchmark

    This benchmark shows critical natives can be several times faster than regular JNI methods when the native workload is very small. The longer is method, the smaller is relative overhead.


    P.S. There is an ongoing work in JDK to implement Native MethodHandles that will serve as a faster alternative to JNI. However it is unlikely to appear prior to 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

提交回复
热议问题