代码之家  ›  专栏  ›  技术社区  ›  Gilgamesz

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

  •  1
  • Gilgamesz  · 技术社区  · 7 年前

    我们有以下代码:

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

    信息技术 似乎 确实有 引用线程堆栈上的直接缓冲区(作为对象)。这意味着这个物体 幻影可达

    • DirectByteBuffer变得可以访问幻影。
    • 执行垃圾收集(在单独的线程中),收集DirectByteBuffer Java对象,并向 引用队列。
    • Cleaner线程到达该条目并运行注册的清理操作(在本例中,它是java.nio.DirectByteBuffer.Deallocator 对象),此操作最终释放本机内存。

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

    因此,分配的内存可能会被释放。然而,我们有一个指向它的指针, buffer 的类型 long 因此,我们有可能得到SIGSEGV或类似的东西。

    我的问题是:

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

    2 回复  |  直到 7 年前
        1
  •  1
  •   BeeOnRope    7 年前

    你对危险的假设是正确的,但有一点需要注意。

    直接缓冲区的后备缓冲区可以在包含ByteBuffer的对象符合垃圾收集条件后的任何时候释放(释放本机内存的确切时间取决于实现,但通常大约在ByteBuffer的终结器运行时发生)。

    从标准Java来看,这个“悬空指针”不会带来真正的问题,因为它和另一个指针一样长,您不能不安全地使用它。当然,如果您将其传递给一些本机或不安全的代码,并尝试将其用作指针,则可能会导致崩溃。

        2
  •  -1
  •   M. le Rutte    7 年前

    严格地说,不是按照您描述的方式,因为您只存储了 long 将值转换为 长的 变量有了这个值,你就不能做任何有害的事情 在Java中

    一旦您将其传递给一些本机(C/C++)代码,并开始使用它作为写入内容的地址,您就会遇到问题,因为对象的内存可能已经被垃圾收集器回收。

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