下面是连接C和Java进程之间Linux的JNI代码。虽然我已经发布了所有的ArrayElements,但是顶级命令的VIRT显示出了巨大的价值。最大堆大小设置为2GB,但顶部显示执行100小时后VIRT为10 2GB。在我看来,这似乎是内存泄漏,但我不知道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;
},这是我编写的mq_send方法
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;
}发布于 2017-04-27 07:32:58
这是旗子的意思作为最后一个参数传递给ReleaseByteArrayElements:
模式标志的可能设置为: 更新Java堆上的数据。释放副本所使用的空间。 JNI_COMMIT更新Java堆上的数据。不要释放副本所使用的空间。 JNI_ABORT不更新Java堆上的数据。释放副本所使用的空间。 “0”模式标志是发布调用最安全的选择。无论数据的副本是否被更改,堆都会使用副本进行更新,并且没有泄漏。
因此,在您的mq_receive函数中,调用传递0的ReleaseByteArrayElements作为最终参数。您不需要SetByteArrayRegion调用,因为数据将由ReleaseByteArrayElements复制回来。
在您的mq_send函数中,您可以传递JNI_ABORT,因为您没有写入数组。
在这两种情况下,这都应该释放缓冲区。
以上假设缓冲区是副本,而不是固定引用。我认为这是一个副本,但是,因为否则不会有泄漏。您可以通过将&isCopy参数传递给GetByteArrayElements来查找。
https://stackoverflow.com/questions/43650572
复制相似问题