J'étais en train de créer une application java lwjgl OpenGL quand j'ai vu que mon utilisation de la RAM augmentait et ne s'arrêtait pas. J'ai commenté ligne par ligne pour trouver la fuite et je l'ai trouvée, la fuite de mémoire se produit lorsque je télécharge une matrice4f (projection dans ce cas) sur le GPU pour que mon vertex shader l'utilise. J'utilise BufferUtils.createFloatBuffer(16); et je le définis sur une variable pour créer le tampon à télécharger sur le shader dans le GPU, la méthode que j'utilise pour cela peut être vue ci-dessous.

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
                        );
}
-2
Random Coder 15 nov. 2020 à 11:42

1 réponse

Meilleure réponse

Premièrement : il n'y a pas de fuite de mémoire là-bas.

BufferUtils.createFloatBuffer() appelle simplement ByteBuffer.allocateDirect() sous le capot pour allouer de la mémoire hors tas (et en plus, il appelle asFloatBuffer() pour obtenir une vue FloatBuffer dessus).

En général, la JVM ne récupère pas la mémoire inaccessible dès que la dernière référence à cette mémoire sort de la portée (c'est-à-dire devient inaccessible). Le sous-système d'allocation de mémoire de la JVM (en particulier le ramasse-miettes) est réglé pour le débit, et non pour une empreinte mémoire minimale.

Et pour atteindre un débit élevé, la JVM ne récupérera de la mémoire non référencée que lorsque cela sera nécessaire, c'est-à-dire lorsque la mémoire système (ou plutôt la quantité maximale de mémoire virtuelle que la JVM a elle-même autorisé à utiliser) atteint l'épuisement.

Donc, finalement, la JVM va récupérer cette mémoire et vous n'obtiendrez aucun OutOfMemoryError.

De plus, en particulier avec les ByteBuffers hors tas, ceux-ci prennent généralement même deux cycles GC complets pour que leur mémoire native soit récupérée par le ramasse-miettes.

Ce que vous pouvez faire pour limiter la quantité de mémoire allouée par la JVM avant que GC ne démarre, est de définir la quantité maximale de mémoire sur tas allouée autorisée avec -Xmx et la quantité maximale de mémoire hors tas allouée autorisée avec -XX:MaxDirectMemorySize.

De plus, LWJGL 3 fournit de nombreuses autres façons d'allouer de la mémoire hors tas. Lire https://blog.lwjgl.org/memory-management-in- lwjgl-3/ pour cela.

1
Kai Burjack 15 nov. 2020 à 09:36