Search code examples
javamemory-leakslwjgl

Buffered utils in lwjgl causing memory leak


I was creating a lwjgl OpenGL java application when I saw that my ram usage went up and up and it did not stop. I commented line by line to find the leak and I found it, the memory leak occurs when I upload a matrix4f (projection in this case) to the GPU for my vertex shader to use. I use BufferUtils.createFloatBuffer(16); and set that to a variable to create the buffer to upload to the shader in the GPU, the method that I use for this can be seen below.

Code:

public void uploadMatrix4f(String variableName, Matrix4f matrix4f) {
        FloatBuffer matrixBuffer = BufferUtils.createFloatBuffer(16); // Leak is occuring here.
        bind(); // This is just making sure that the shader that this is getting uploaded to is used.
        matrix4f.get(matrixBuffer);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgramID, variableName),
                        false,
                        matrixBuffer
                        );
}

Solution

  • First: There is no memory leak there.

    BufferUtils.createFloatBuffer() simply calls ByteBuffer.allocateDirect() under the hood to allocate off-heap memory (and additionally, it calls asFloatBuffer() to get a FloatBuffer view on it).

    In general, the JVM does not reclaim unreachable memory as soon as the last reference to that memory goes out of scope (i.e. becomes unreachable). The JVM's memory allocation subsystem (in particular the garbage collector) is tuned for throughput, not for minimal memory footprint.

    And to achieve high throughput, the JVM will only reclaim unreferenced memory when there is a need to do so, that is, when the system memory (or rather the maximum amount of virtual memory that the JVM has itself allowed to use) reaches exhaustion.

    So, eventually, the JVM will reclaim that memory and you won't get any OutOfMemoryError.

    Also, in particular with off-heap ByteBuffers, those take typically even two whole full GC cycles to have their native memory reclaimed by the garbage collector.

    What you can do to limit the amount of memory allocated by the JVM before GC kicks in, is to set the maximum amount of allowed allocated on-heap memory with -Xmx and the maximum amount of allowed allocated off-heap memory with -XX:MaxDirectMemorySize.

    In addition, LWJGL 3 provides many more ways to allocate off-heap memory. Read https://blog.lwjgl.org/memory-management-in-lwjgl-3/ for this.