Нужно ли освобождать выделенный ByteBuffer вручную? - PullRequest
2 голосов
/ 29 марта 2019

Я пишу некоторые вещи, которые используют ByteBuffer с.В документах API говорится:

Нет способа явно освободить буфер (без специфического отражения JVM). Буферные объекты подчиняются GC , и обычно требуется два цикла GC для освобождения памяти вне кучи после того, как буферный объект становится недоступным.

Однако в сообщении SOпринятый ответ Я прочитал

BigMemory использует адресное пространство памяти процесса JVM через прямые байтовые буферы, которые не подчиняются GC в отличие от других собственных объектов Java.

Что мне теперь делать, освободить созданный буфер?Или я что-то неправильно понимаю в документах или ответе?

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Как сказано в документации BufferUtils в LWJGL: нет способа явно освободить a ByteBuffer.

Объекты ByteBuffer, которые выделяются стандартным механизмом (а именно прямым или косвенным вызовом ByteBuffer#allocateDirect), подлежат 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);
    }
}
1 голос
/ 29 марта 2019

Зависит от того, как вы создаете буфер, есть много возможных вариантов использования. Обычные ByteBuffer.allocate() будут создаваться в куче и будут собираться GC. Другие варианты, например родная память не может.

Terracotta BigMemory - это тип собственной памяти вне кучи, которая не регулируется GC JVM. Если вы выделяете буфер в памяти такого типа, вы должны очистить его самостоятельно.

Это может быть хорошей идеей для очистки буфера, даже если он расположен в памяти кучи. GC позаботится о сборе неиспользованного буфера, но это займет некоторое время.

...