释放java中的直接缓冲区和可能的陷阱

时间:2018-04-21 19:15:48

标签: java nio bytebuffer direct-buffer

我们有以下代码:

long buffer = ((DirectBuffer) ByteBuffer.allocateDirect(256)).address(); 

似乎在线程堆栈上有直接缓冲区(作为对象)的 no 引用。因此,这意味着该对象是幻像可达

  
      
  • DirectByteBuffer变为幻像可达。
  •   
  • 执行垃圾收集(在单独的线程中),收集DirectByteBuffer Java对象并将一个条目添加到   的ReferenceQueue。
  •   
  • 清洁线程到达此条目并运行已注册的清理操作(在本例中,它是java.nio.DirectByteBuffer.Deallocator   对象),这个动作最终释放了本机内存。
  •   

引用来自:Java - When does direct buffer released?

因此,可以释放已分配的内存。但是,我们有一个指向buffer类型long的指针。因此,我们有可能获得SIGSEGV或类似的东西。

我的问题是:

这是否意味着我们可以以这种方式使用DirectBuffer来伤害自己?

2 个答案:

答案 0 :(得分:1)

您的危险假设是正确的,但请注意。

在包含的ByteBuffer对象成为垃圾回收的条件之后,可以随时释放直接缓冲区的后备缓冲区(释放本机内存的确切时间取决于实现,但通常在ByteBuffer的终结器运行时发生)。

从标准Ja​​va来看,这种“悬空指针”并没有造成真正的问题,因为它和其他指针一样长,并且您不能不安全地使用它。当然,如果将其传递给某些本机代码或不安全代码,并尝试将其用作指针,则事情可能会崩溃。

答案 1 :(得分:-1)

严格地说,不是按照您描述的确切方式,因为您只是将long值存储到long变量中。使用此值,您无法在Java 中执行任何有害的

一旦你将它传递给一些本地(C / C ++)代码并开始使用它作为写东西的地址给你自己陷入问题,因为对象的记忆可能已经被回收了垃圾收集器。

因此,所有这些访问都应该在本机代码(JNI)中完成,您可以使用本机API告诉虚拟机您的本机代码是否包含引用(或不再存在)。您可以使用本机代码中的address()函数获取地址并使用它。