在 java 中释放直接缓冲区和可能的陷阱
Releasing a direct buffer in java and possible pitfalls
我们有如下一段代码:
long buffer = ((DirectBuffer) ByteBuffer.allocateDirect(256)).address();
似乎线程堆栈上没有对直接缓冲区(作为对象)的引用。所以,这意味着该对象是 幻影可达.
- DirectByteBuffer becomes phantom-reachable.
- Garbage collection is performed (in separate thread), DirectByteBuffer Java object is collected and an entry is added to the
ReferenceQueue.
- Cleaner thread reaches this entry and runs the registered clean-up action (in this case, it's java.nio.DirectByteBuffer.Deallocator
object), this action finally frees the native memory.
引文来自:
因此,有可能分配的内存可以释放。但是,我们有一个指向它的指针,类型为 long
的 buffer
。因此,我们有可能得到 SIGSEGV 或类似的东西。
我的问题是:
这是否意味着我们会以这种方式使用 DirectBuffer 伤害自己?
严格来说,并不是按照您描述的那样,因为您只是将 long
值存储到 long
变量中。使用此值,您可以在 Java.
中做任何有害的事情
一旦您将其传递给某些本机 (C/C++) 代码并开始将其用作向其写入内容的地址,您就会陷入问题,因为对象的内存可能已经被回收由垃圾收集器。
因此,所有这些访问都应该在本机代码 (JNI) 中完成,您可以在本机代码中使用本机 API 告诉虚拟机您的本机代码持有一个引用(或不再持有)。然后,您可以在本机代码中使用 address()
函数来获取地址并使用它。
您对这里的危险假设是正确的,但需要注意。
在包含的 ByteBuffer 对象符合垃圾回收条件后,可以随时释放直接缓冲区的后备缓冲区(释放本机内存的确切时间取决于实现,但通常大约发生在字节缓冲区运行)。
从标准 Java 来看,这个 "dangling pointer" 不会造成真正的问题,因为它和另一个一样长,你不能不安全地使用。当然,如果您将它传递给某些本机代码或不安全代码并尝试将其用作指针,事情可能会崩溃。
我们有如下一段代码:
long buffer = ((DirectBuffer) ByteBuffer.allocateDirect(256)).address();
似乎线程堆栈上没有对直接缓冲区(作为对象)的引用。所以,这意味着该对象是 幻影可达.
- DirectByteBuffer becomes phantom-reachable.
- Garbage collection is performed (in separate thread), DirectByteBuffer Java object is collected and an entry is added to the ReferenceQueue.
- Cleaner thread reaches this entry and runs the registered clean-up action (in this case, it's java.nio.DirectByteBuffer.Deallocator object), this action finally frees the native memory.
引文来自:
因此,有可能分配的内存可以释放。但是,我们有一个指向它的指针,类型为 long
的 buffer
。因此,我们有可能得到 SIGSEGV 或类似的东西。
我的问题是:
这是否意味着我们会以这种方式使用 DirectBuffer 伤害自己?
严格来说,并不是按照您描述的那样,因为您只是将 long
值存储到 long
变量中。使用此值,您可以在 Java.
一旦您将其传递给某些本机 (C/C++) 代码并开始将其用作向其写入内容的地址,您就会陷入问题,因为对象的内存可能已经被回收由垃圾收集器。
因此,所有这些访问都应该在本机代码 (JNI) 中完成,您可以在本机代码中使用本机 API 告诉虚拟机您的本机代码持有一个引用(或不再持有)。然后,您可以在本机代码中使用 address()
函数来获取地址并使用它。
您对这里的危险假设是正确的,但需要注意。
在包含的 ByteBuffer 对象符合垃圾回收条件后,可以随时释放直接缓冲区的后备缓冲区(释放本机内存的确切时间取决于实现,但通常大约发生在字节缓冲区运行)。
从标准 Java 来看,这个 "dangling pointer" 不会造成真正的问题,因为它和另一个一样长,你不能不安全地使用。当然,如果您将它传递给某些本机代码或不安全代码并尝试将其用作指针,事情可能会崩溃。