簡體   English   中英

通過JNI將數據從C傳遞到Java的快速方法

[英]Fast way to pass data from C to Java via JNI

我在c中使用了一些快速通信庫,但我的應用程序的其余部分是用Java編寫的。 所以我想將收到的數據傳遞給我的java應用程序。

作為測試,我每隔5ms收到1000次消息。 這導致發件人應用程序完成發送時。 接收器應用程序仍需要時間來處理數據。

如果我刪除該行

(*g_env)->CallVoidMethod(g_env, store_callback, methodHandleMessage, top,
    ts, fo, msg);

接收方應用程序在發送方發送完最后一條消息后立即完成。

有沒有機會加快速度?

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

}

您可以通過將類標記為final來節省handleMessage調用的一些時間,這將消除執行虛擬查找的需要。

如果這還不夠,並且如果不需要異步調用handleMessage則可以避免直接調用它,而是將參數存儲在您將創建和管理的本地C數組中。 然后,您可以通過使用MonitorEnter鎖定它,調用GetMethodID(g_env, clazz, "notify", "()V") ,然后使用MonitorExit解鎖來通知Java對象可用的數據。

然后在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]);
        }
    }
}

回到原生的一面,你需要實現getBufferedArgumentsViaJNI來返回並清除所有緩沖參數的JNI數組(作為練習留給讀者)。

作為一個精明的讀者,您可能想知道為什么這會更快,因為您仍然需要在onMessageReceived調用JNI方法以及執行JNI同步,因此它仍然會產生JNI開銷。 答案是雖然我不能保證消息處理總體上更快,但是“wait”調用可能會明顯加快,因為wait()作為我見過的每個JVM上的本機方法實現。

java方法可能為空,但每次仍然調用GetEnv(),並創建4個復制到Java的字符串。 這些字符串有多大? 我試着用一些10-20個字符的字符串調用這個方法並測量它。 另一個簡單的解決方案(如果方法調用非常慢)用數組而不是字符串調用它,甚至可能將幾個字符串打包到一個數組中。 或者你也可以使用共享緩沖區( http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#GetDirectBufferAddress

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM