TextRenderer memory leak?

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

TextRenderer memory leak?

farrellf
I use a few TextRenderers to draw lots of text every frame. I noticed a slow memory leak, and I believe it is inside the TextRenderers. If I replace them after an hour of rendering (with myRenderer = new TextRenderer(...);) the garbage collector can immediately free up ~20MB for each TextRenderer. If I let my program run overnight, the memory leak gets massive.

I tried flush()'ing each TextRenderer every frame, but that does not seem to help. Am I doing something wrong?

I can provide a minimalist example if needed. I'm using Java 8 on Windows 10.

Thanks,
-Farrell
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

gouessej
Administrator
Hello

Do you use the legacy text renderer? I don't think that you're doing something wrong. What does JVisualVM indicate in your case?
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

farrellf
"Legacy"? Is there a newer way to do it?

I wrote a minimalist demo. To make the leak quick, I have 1000 TextRenderers. Here's what it looks like after 10 minutes. Toward the end I replace the TextRenderer objects with new ones, confirming that the old ones were getting very big.

https://imgur.com/a/3SCmPmr

Source code:

import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.awt.TextRenderer;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Date;

import javax.swing.JFrame;

public class MainMemoryLeak {
       
        static TextRenderer tr[] = new TextRenderer[1000];
       
        public static void main(String[] args) {

                GLCanvas glcanvas = new GLCanvas(new GLCapabilities(GLProfile.get(GLProfile.GL2)));
                glcanvas.addGLEventListener(new GLEventListener() {
                       
                        int width = 0;
                        int height = 0;
                       
                        @Override public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
                               
                                width = w;
                                height = h;
                               
                                GL2 gl = drawable.getGL().getGL2();
                               
                                gl.glMatrixMode(GL2.GL_PROJECTION);
                                gl.glLoadIdentity();
                                gl.glOrtho(0, width, 0, height, -1, 1);
                               
                                gl.glMatrixMode(GL2.GL_MODELVIEW);
                                gl.glLoadIdentity();
                               
                        }
                       
                        @Override public void init(GLAutoDrawable drawable) {

                                for(int i = 0; i < 1000; i++)
                                        tr[i] = new TextRenderer(glcanvas.getFont(), true, true);
                               
                        }
                       
                        @Override public void dispose(GLAutoDrawable drawable) {
                               
                        }
                       
                        @Override public void display(GLAutoDrawable drawable) {
                                       
                                GL2 gl = drawable.getGL().getGL2();
                               
                                gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

                                for(int i = 0; i < 1000; i++) {
                                        tr[i].beginRendering(width, height);
                                        tr[i].setColor(Color.WHITE);
                                        tr[i].draw((new Date()).toString(), 10, 10 + i);
                                        tr[i].endRendering();
                                        tr[i].flush();
                                }
                               
                                gl.glFlush();
                               
                        }
                       
                });
               
                glcanvas.addKeyListener(new KeyListener() {
                       
                        @Override public void keyPressed(KeyEvent e) {
                                if(e.getKeyChar() == 'a') {
                                        System.out.println("Replacing the TextRenderers.");
                                        for(int i = 0; i < 1000; i++)
                                                tr[i] = new TextRenderer(glcanvas.getFont(), true, true);
                                }
                        }
                       
                        @Override public void keyTyped(KeyEvent e) { }
                        @Override public void keyReleased(KeyEvent e) { }
                       
                });
               
                JFrame frame = new JFrame("Memory Leak Demo, After several minutes: click in the window, then press 'a' to see the leak disappear.");
                frame.add(glcanvas);
                frame.setSize(700, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
       
                Animator anim = new Animator(glcanvas);
                anim.start();
               
        }
       
}
Is there a better way to do text? If not, is there a way to query the size of a TextRenderer so I can replace it when it gets a certain size? If not, is the best workaround to just replace each TextRenderer every n frames?

-Farrell
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

gouessej
Administrator
You're using the legacy text renderer. Maybe the glyph cache becomes very big. You should look more in depth at the information provided by the memory sampler in JVisualVM.

P.S: Please can you test this patch?
https://jogamp.org/bugzilla/show_bug.cgi?id=1101
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

Sven Gothel
Administrator
On 8/20/19 12:34 PM, gouessej [via jogamp] wrote:
> You're using the legacy text renderer. Maybe the glyph cache becomes very big.
> You should look more in depth at the information provided by the memory
> sampler in JVisualVM.

FYI, I have applied Bug 1101's patch and pushed that one,
i.e. the VBO leak.

Thank you for pushing Julien,
always important to have a good overview.

~Sven
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

farrellf
In reply to this post by gouessej
I get the memory leak even with "tr[i].setUseVertexArrays(false);" so I'm guessing VBOs are not the only thing at play. VisualVM shows lots of int[] for GlyphProducer and Glyph:

https://imgur.com/a/1DktskI

I have not tried the patch yet. Is there a guide on how to build everything on Windows and package it into Jars?

-Farrell
Reply | Threaded
Open this post in threaded view
|

Re: TextRenderer memory leak?

Sven Gothel
Administrator
On 8/21/19 2:27 AM, farrellf [via jogamp] wrote:
> I get the memory leak even with "tr[i].setUseVertexArrays(false);" so I'm
> guessing VBOs are not the only thing at play. VisualVM shows lots of int[] for
> GlyphProducer and Glyph:
>
> https://imgur.com/a/1DktskI

The given patch does not target this class of 'leaks',
as the path addresses the VBO leak.
Quoted b/c I haven't looked into your issue yet.

BTW .. JOGL' graph package contains a text renderer
utilizing the GPU. You will find some posts about it here
and on demos on JogAmp.

>
> I have not tried the patch yet. Is there a guide on how to build everything on
> Windows and package it into Jars?

When you clone the 'java11' branch, which contains the one patch,
you will find a doc/HowToBuild.html which is very much up-to-date.

~Sven

>
> -Farrell
>