我们必须手动释放分配的 ByteBuffer 吗?

Do we have to free an allocated ByteBuffer manually?

我正在写一些使用 ByteBuffer 的东西。在 docs of the API 它说

There is no way to free a buffer explicitly (without JVM specific reflection). Buffer objects are subject to GC and it usually takes two GC cycles to free the off-heap memory after the buffer object becomes unreachable.

然而在 SO post's accepted answer 我读了

BigMemory uses the memory address space of the JVM process, via direct ByteBuffers that are not subject to GC unlike other native Java objects.

现在我该怎么办,我应该释放创建的缓冲区吗?还是我误解了文档或答案中的某些内容?

这取决于您如何创建缓冲区,有很多可能的用例。 RegularByteBuffer.allocate()会在堆上创建,会被GC回收。其他选项,例如本机内存可能不会。

Terracotta BigMemory 是一种不受 JVM GC 控制的原生堆外内存。如果你在这种类型的内存中分配一个缓冲区,你必须自己清除它。

清除缓冲区可能是个好主意,即使它是在堆内存中分配的。 GC 将负责收集未使用的缓冲区,但这需要一些时间。

LWJGL 中 BufferUtils 的文档也说:没有办法显式 free a ByteBuffer

标准机制(即直接或间接调用ByteBuffer#allocateDirect)分配的ByteBuffer个对象会被GC,最终会被清理掉。

您链接到的答案似乎特别提到了 BigMemory 库。使用 JNI,您 可以 创建一个(直接) ByteBffer ,它 由 GC 处理,这取决于您实际释放底层数据。


但是,一个简短的建议:在处理 LWJGL 和其他依赖(直接)ByteBuffer 对象将数据传输到本机端的库时,您应该考虑这些缓冲区的使用模式。特别是对于 OpenGL 绑定库,您经常需要一个 ByteBuffer,它只有 space 用于 16 个 float 值,例如(例如,包含一个发送到 OpenGL 的矩阵)。在许多情况下,使用这些缓冲区进行数据传输的方法将被频繁调用。

在这种情况下,重复分配这些小的、短暂的缓冲区通常不是一个好主意:

class Renderer {
    void renderMethodThatIsCalledThousandsOfTimesPerSecond() {
        ByteBuffer bb = ByteBuffer.allocateDirect(16 * 4);
        fill(bb);
        passToOpenGL(bb);
    }
}

创建这些缓冲区和 GC 会显着降低性能 - 令人沮丧的是,GC 暂停会导致游戏延迟。

对于这种情况,提取分配并重新使用缓冲区可能是有益的:

class Renderer {

    private final ByteBuffer MATRIX_BUFFER_4x4 = ByteBuffer.allocateDirect(16 * 4);

    void renderMethodThatIsCalledThousandsOfTimesPerSecond() {
        fill(MATRIX_BUFFER_4x4);
        passToOpenGL(MATRIX_BUFFER_4x4);
    }
}