我们有以下代码:
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来伤害自己?
答案 0 :(得分:1)
您的危险假设是正确的,但请注意。
在包含的ByteBuffer对象成为垃圾回收的条件之后,可以随时释放直接缓冲区的后备缓冲区(释放本机内存的确切时间取决于实现,但通常在ByteBuffer的终结器运行时发生)。
从标准Java来看,这种“悬空指针”并没有造成真正的问题,因为它和其他指针一样长,并且您不能不安全地使用它。当然,如果将其传递给某些本机代码或不安全代码,并尝试将其用作指针,则事情可能会崩溃。
答案 1 :(得分:-1)
严格地说,不是按照您描述的确切方式,因为您只是将long
值存储到long
变量中。使用此值,您无法在Java 中执行任何有害的。
一旦你将它传递给一些本地(C / C ++)代码并开始使用它作为写东西的地址给你自己陷入问题,因为对象的记忆可能已经被回收了垃圾收集器。
因此,所有这些访问都应该在本机代码(JNI)中完成,您可以使用本机API告诉虚拟机您的本机代码是否包含引用(或不再存在)。您可以使用本机代码中的address()
函数获取地址并使用它。