JNI直接缓冲区。谁负责本地缓冲区的释放?

11
假设我们手头有一个使用env->NewDirectByteBuffer()创建的直接字节缓冲区,另一方面,我们有一个类似的直接缓冲区,但是使用ByteBuffer.allocateDirect()创建。显然,这两个对象应该以相同的方式由JVM管理,包括对后备本机缓冲区的管理,在第一种情况下,用户提供了后备本机缓冲区,在第二种情况下,JVM从本机堆中分配了后备缓冲区。
当GC第二个使用ByteBuffer.allocateDirect()实例化的对象时,JVM必须释放背景缓冲区。
我的问题是:JVM在GC第一个使用env->NewDirectByteBuffer()实例化的对象时会尝试释放缓冲区吗?
注:我在JNI文档和SO上都没有找到明确的答案。最有用的信息在这里http://www.ibm.com/developerworks/library/j-nativememory-linux/index.html
直接的ByteBuffer对象自动清除其本地缓冲区,但只能作为Java堆GC的一部分执行此操作 - 因此它们不会自动响应于本机堆上的压力。
因此,看起来JVM将在GC传递期间释放后备缓冲区,但没有任何关于解除分配器的提及。是纯粹的free()还是其他东西?
1个回答

12

当您调用JNI NewDirectByteBuffer(void* address, jlong capacity)时,将创建一个DirectByteBuffer对象,使用以下构造函数:

private DirectByteBuffer(long addr, int cap) {
    super(-1, 0, cap, cap);
    address = addr;
    cleaner = null;
    att = null;
}

请注意,cleaner属性为null。

如果你通过ByteBuffer.allocateDirect()创建一个DirectByteBuffer, 则cleaner属性会被设置(参见DirectByteBuffer的源代码)。

现在,cleaner是一个实用程序对象,其clean方法在缓冲区被垃圾回收时运行(有关详细信息,请参见此解释)。

对于通过ByteBuffer.allocateDirect()构造的缓冲区,cleaner将释放直接内存。

对于通过JNI构建的缓冲区,没有执行这样的操作。您需要自己释放这段内存。


清除。似乎安卓使用相同的方法。安卓SDK有详尽的注释:/** * 表示我们不拥有的一块内存。(我们不接管由JNI NewDirectByteBuffer函数创建的直接缓冲区对应的内存。) */ - Sergio
这是最近一些最好的问答,似乎没有人知道这个。 - haelix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接