【问题标题】:Do we have to free an allocated ByteBuffer manually?我们必须手动释放分配的 ByteBuffer 吗?
【发布时间】:2019-08-20 10:10:15
【问题描述】:

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

没有办法显式释放缓冲区(没有 JVM 特定的 反射)。 缓冲区对象会受到GC,通常需要两次 缓冲区对象变为后,GC 循环释放堆外内存 无法访问。

但是在SO post's accepted answer我读到

BigMemory 使用 JVM 进程的内存地址空间,通过直接 不受 GC 影响的 ByteBuffers 与其他原生 Java 不同 对象。

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

【问题讨论】:

  • 会的。 Papa Google 首先弹出了文档,然后是一些导致误解的 SO 帖子,因此出现了问题。对于我和其他任何可能偶然发现这篇文章的人来说,这里有这个链接是件好事。

标签: java lwjgl nio


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢,但混淆的原因是部分通过不受 GC 约束的直接 ByteBuffers。所以 Terracotta BM 以不同的方式使用ByteBuffers?还是他们的同名只是巧合?
【解决方案2】:

正如 LWJGL 中 BufferUtils 的文档中所说:没有办法明确释放 ByteBuffer

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

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


但是,一个简短的建议:在处理 LWJGL 和其他依赖(直接)ByteBuffer 对象以将数据传输到本机端的库时,您应该考虑这些缓冲区的使用模式。特别是对于 OpenGL 绑定库,您将经常需要一个 ByteBuffer,它只有 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);
    }
}

【讨论】:

  • 感谢您的回答,出于性能原因,非常值得一提。现在我只是在 Java 代码中使用 assimp 并且担心内存泄漏。
猜你喜欢
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多