【问题标题】:Freeing jni references from memory从内存中释放 jni 引用
【发布时间】:2011-08-01 06:05:27
【问题描述】:

我在 java 中创建了一个字节数组,并通过引用 jni 函数来传递它。我在循环中执行此操作,有时会在 jni 中出现内存不足错误。我想知道java是否在每次迭代时自动释放数组,或者因为它被传递给jni函数,它不会??

JNI 代码(bOldArray 是我作为参数传递给 jni 的 java 字节数组)

len = (*env)->GetArrayLength(env,bOldArray);
char *oldBuff = (char *)calloc(sizeof(char),MAX_SIZE);
jbyte* bytes = (*env)->GetByteArrayElements(env,bOldArray,0);
memcpy(oldBuff,bytes,len);
(*env)->ReleaseByteArrayElements(env,bOldArray,(jbyte *)bytes,0);

【问题讨论】:

  • 似乎仍然找不到错误。

标签: java-native-interface android-ndk bytearray


【解决方案1】:

你在这里有 2 个缓冲区,一个来自你的 java 代码 (bOldArray) 和你在第 2 行分配的本地缓冲区 (oldbuff)。

事实上,你可能有更多的缓冲区,因为

(*env)->GetArrayLength 

with 几乎可以肯定地制作了一个不可移动的内存副本(c-pointer-access 需要),它将数组保存在你的 java 代码中和 with

(*env)->ReleaseByteArrayElements(env,bOldArray,(jbyte *)bytes,0);

此内存被复制回您的 java 数组的内存中(查看 ReleaseByteArrayElements 的最后一个参数的文档)

但是关于你的问题:你也应该释放 oldBuff。

free(oldBuff);

否则,VM 确实释放了您的 java 数组的 c 副本,但没有直接释放自分配的部分(由于对象生命周期和垃圾收集,它可能稍后会这样做,但这是不可预测的,因此无法内存错误也是不可预知的)

为了避免 java-c-copy 机制(加速性能),请使用共享/静态缓冲区,例如 ByteBuffer

【讨论】:

    【解决方案2】:

    如果你使用GetByteArrayElements,你必须在JNI 中处理完数组后调用ReleaseByteArrayElements,因为JVM 会阻止在java 中释放这个数组,直到你这样做。 请发布代码以获得更清晰的想法

    【讨论】:

    • 看起来java数组的发布做得很好。一些建议。您可以使用 len 而不是 MAX_SIZE 进行调用。另外,如果这个函数在循环中被调用,你将不得不在某个时候释放 oldBuff
    • 感谢您的建议。是的,我在返回 jni 之前释放了 oldBuff。
    • 澄清一下,当你从 java 循环调用这个 JNI 函数时,你仍然得到一个 OutOfMemory 吗?这是获得 OutOfMemory 所需的唯一代码吗?当 calloc 失败时,您还会收到 OutOfMemoryError 作为 Java 抛出的错误,还是从本机代码中看到?
    • 是的,我失忆了。是的,当 calloc 失败时,它是本机代码看到的唯一代码
    • 您发布的代码看起来不错,只要您确定正确释放它即可。尝试并确保在再次调用 calloc 之前始终释放 oldBuff。想不出别的了,除非你贴出完整的代码
    猜你喜欢
    • 2012-04-06
    • 1970-01-01
    • 2010-12-04
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 2011-01-18
    • 1970-01-01
    相关资源
    最近更新 更多