通过JNI将数据从C传递到Java的快速方法

use*_*938 5 c java java-native-interface

我在c中使用了一些快速通信库,但我的应用程序的其余部分是用Java编写的.所以我想将收到的数据传递给我的java应用程序.

作为测试,我每隔5ms收到1000次消息.这导致发件人应用程序完成发送时.接收器应用程序仍需要时间来处理数据.

如果我删除该行

(*g_env)->CallVoidMethod(g_env, store_callback, methodHandleMessage, top,
    ts, fo, msg);
Run Code Online (Sandbox Code Playgroud)

接收方应用程序在发送方发送完最后一条消息后立即完成.

有没有机会加快速度?

void onMessageReceived(char* topic, char* timestamp, char* format,
    char* message) {
JNIEnv * g_env;
int getEnvStat = (*g_vm)->GetEnv(g_vm, (void **) &g_env,
JNI_VERSION_1_8);
if (getEnvStat == JNI_EDETACHED) {
    if ((*g_vm)->AttachCurrentThread(g_vm, (void **) &g_env, NULL) != 0) {
        puts("Failed to attach");
        fflush(stdout);
    }
}

if (methodHandleMessage) {
} else {
    jclass clazz = (*g_env)->GetObjectClass(g_env, store_callback);
    methodHandleMessage =
            (*g_env)->GetMethodID(g_env, clazz, "handleMessage",
                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");

}
jstring top = (*g_env)->NewStringUTF(g_env, topic);
jstring ts = (*g_env)->NewStringUTF(g_env, timestamp);
jstring fo = (*g_env)->NewStringUTF(g_env, format);
jstring msg = (*g_env)->NewStringUTF(g_env, message);

 //This line takes too long!
(*g_env)->CallVoidMethod(g_env, store_callback, methodHandleMessage, top,
        ts, fo, msg);

}
Run Code Online (Sandbox Code Playgroud)

mar*_*rux 0

您可以handleMessage通过将类标记为 来节省一些调用时间final,这将消除执行虚拟查找的需要。

如果这还不够,并且handleMessage不需要异步调用,您可以避免直接调用它,而是将参数存储在您将创建和管理的本地 C 数组中。然后,您可以通过使用 锁定 Java 对象MonitorEnter、调用GetMethodID(g_env, clazz, "notify", "()V")然后使用 解锁来通知 Java 对象有一些数据可用MonitorExit

然后在 Java 方面,实例store_callback将有一个专门的线程来等待通知,如下所示:

while (true) {
    synchronized (self) {
        wait();
        // we were informed that we received new data: now pull it out and process
        String[][] args = getBufferedArgumentsViaJNI();
        for (String[] arg : args) {
            handleMessage(arg[0], arg[1], arg[2], arg[3]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

回到本机方面,您需要实现getBufferedArgumentsViaJNI返回并清除所有缓冲参数的 JNI 数组(留给读者作为练习)。

作为一个精明的读者,您可能想知道为什么这会更快,因为您仍然需要调用 JNI 方法并onMessageReceived执行 JNI 同步,因此它仍然会产生 JNI 开销。答案是,虽然我不能保证消息处理总体上会更快,但“等待”调用可能会明显更快,因为它wait()是在我见过的每个 JVM 上作为本机方法实现的。