agiro
agiro

Reputation: 2080

Do we have to free an allocated ByteBuffer manually?

I'm writing some stuff that uses ByteBuffers. In the docs of the API it says

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.

However in a SO post's accepted answer I read

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

Now what should I do, shall I free the created buffer? Or do I misunderstand something in the docs or the answer?

Upvotes: 7

Views: 5626

Answers (2)

Marco13
Marco13

Reputation: 54649

As the documentation of the BufferUtils in LWJGL also say: There is no way to explicitly free a ByteBuffer.

The ByteBuffer objects that are allocated with the standard mechanism (namely, by directly or indirectly calling ByteBuffer#allocateDirect) are subject to GC, and will be cleaned up eventually.

The answer that you linked to seems to refer to the BigMemory library in particular. Using JNI, you can create a (direct) ByteBffer that is not handled by the GC, and where it is up to you to actually free the underlying data.


However, a short advice: When dealing with LWJGL and other libraries that rely on (direct) ByteBuffer objects for the data transfer to the native side, you should think about the usage pattern of these buffers. Particularly for OpenGL binding libraries, you'll frequently need a ByteBuffer that only has space for 16 float values, for example (e.g. containing a matrix that is sent to OpenGL). And in many cases, the methods that do the data transfer with these buffers will be called frequently.

In such a case, it is usually not a good idea to allocate these small, short-lived buffers repeatedly:

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

The creation of these buffers and the GC can significantly reduce performance - and distressingly in the form of GC pauses, that could cause lags in a game.

For such cases, it can be beneficial to pull out the allocation, and re-use the buffer:

class Renderer {

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

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

Upvotes: 3

Karol Dowbecki
Karol Dowbecki

Reputation: 44962

It depends how you create the buffer, there are many possible use cases. Regular ByteBuffer.allocate() will be created on the heap and will be collected by the GC. Other options e.g. native memory might not.

Terracotta BigMemory is a type of native off-heap memory which is not governed by the JVM GC. If you allocate a buffer in this type of memory you have to clear it yourself.

It might be a good idea to clear the buffer even if it's allocated in the heap memory. GC will take care of collecting unused buffer it but this will take some time.

Upvotes: 4

Related Questions