2017-04-27 106 views
2

下面是在C和Java進程之間橋接Linux MQ的JNI代碼。儘管我已經發布了所有的ArrayElements,但是頂級命令的VIRT仍然顯示出巨大的價值。最大堆大小設置爲2GB,但在執行100小時後顯示VIRT的頂部爲10GB。它看起來像是一個內存泄漏,但是,我無法弄清楚JNI代碼的哪一部分導致了這個問題。如果有人能幫助我一點,這會很好。謝謝。JNI代碼中的內存泄漏

我的JDK版本爲1.8.0_91

這是則mq_receive方法我寫

JNIEXPORT int JNICALL Java_test_ipc_impl_LinuxMessageQueue_mq_1receive(
     JNIEnv *env, jobject self, jint mqdes, jbyteArray buffer, jint msglen) { 
    jbyte* buf = (*env)->GetByteArrayElements(env, buffer, NULL); 
    if ((*env)->ExceptionCheck(env)) 
     return -1; 

    struct timespec timeout; 

    clock_gettime(CLOCK_REALTIME, &timeout); 
    timeout.tv_sec += 1; 

    int size = mq_timedreceive(mqdes, (char*) buf, msglen, 0, &timeout); 

    if (size == -1) { 
     if (errno == ETIMEDOUT) { 
      size = 0; 
     } else { 
      perror("mq_receive fail"); 
     } 
    } else { 
     (*env)->SetByteArrayRegion(env, buffer, 0, size, buf); 
     if ((*env)->ExceptionCheck(env)) 
      return -1; 
    } 

    (*env)->ReleaseByteArrayElements(env, buffer, buf, JNI_COMMIT); 
    if ((*env)->ExceptionCheck(env)) 
     return -1; 

    return size; 
} 

而且,這是我寫的

JNIEXPORT void JNICALL Java_test_ipc_impl_LinuxMessageQueue_mq_1send(
     JNIEnv *env, jobject self, jint mqdes, jbyteArray buffer, jint msglen) { 
    jbyte* buf = (*env)->GetByteArrayElements(env, buffer, NULL); 
    if ((*env)->ExceptionCheck(env)) 
     return; 

    if (mq_send(mqdes, (char*) buf, msglen, 0) == -1) { 
     perror("mq_send fail"); 
    } 
    (*env)->ReleaseByteArrayElements(env, buffer, buf, JNI_COMMIT); 
    if ((*env)->ExceptionCheck(env)) 
     return; 

} 

回答

2

Here's the meaning of the flags的則mq_send方法作爲最後一個參數傳遞給ReleaseByteArrayElements

模式標誌的可能的設置包括:

更新在Java堆中的數據。釋放副本使用的空間。

JNI_COMMIT 更新Java堆上的數據。不要釋放副本使用的空間。

JNI_ABORT 不要更新Java堆上的數據。釋放副本使用的空間。

「0」模式標誌是發佈呼叫的最安全選擇。無論數據的副本是否更改,堆都會隨副本一起更新,並且沒有泄漏。

因此,在您的mq_receive函數中,調用ReleaseByteArrayElements將0作爲最終參數。您不需要撥打SetByteArrayRegion,因爲數據將被複制回ReleaseByteArrayElements

在您的mq_send函數中,您可以傳遞JNI_ABORT,因爲您沒有寫入數組。

這應該在兩種情況下釋放緩衝區。

上面假設緩衝區是一個副本而不是固定參考。我認爲這是一個副本,否則就不會有泄漏。您可以通過將&isCopy參數傳遞給GetByteArrayElements

+0

非常感謝。將嘗試出來tmr –

+0

提到的解決方案確實工作 –