JNI 代码中的内存泄漏
Posted
技术标签:
【中文标题】JNI 代码中的内存泄漏【英文标题】:Memory leak in JNI code 【发布时间】:2017-04-27 06:52:11 【问题描述】:下面是在 C 和 Java 进程之间桥接 Linux MQ 的 JNI 代码。虽然我已经发布了所有的 ArrayElements,但是 top 命令的 VIRT 仍然显示出巨大的价值。最大堆大小设置为 2GB,但顶部显示 VIRT 在执行 100 小时后为 10GB。对我来说,这看起来像是内存泄漏,但是,我无法弄清楚 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;
【问题讨论】:
【参考方案1】:Here's the meaning of the flags 作为最后一个参数传递给ReleaseByteArrayElements
:
模式标志的可能设置是:
0 更新 Java 堆上的数据。释放副本使用的空间。
JNI_COMMIT 更新 Java 堆上的数据。不要释放副本使用的空间。
JNI_ABORT 不要更新 Java 堆上的数据。释放副本使用的空间。
“0”模式标志是 Release 调用最安全的选择。无论数据的副本是否发生变化,堆都随着副本更新,并且没有泄漏。
因此,在您的 mq_receive
函数中,调用 ReleaseByteArrayElements
并传递 0 作为最终参数。您不需要SetByteArrayRegion
调用,因为数据将由ReleaseByteArrayElements
复制回来。
在您的 mq_send
函数中,您可以传递 JNI_ABORT
,因为您没有写入数组。
这应该在两种情况下都释放缓冲区。
以上假设缓冲区是副本而不是固定引用。我认为这是一个副本,否则不会有泄漏。您可以通过将&isCopy
参数传递给GetByteArrayElements
来找出答案。
【讨论】:
非常感谢。会试试看tmr以上是关于JNI 代码中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章